2012-10-13 172 views
3

我想从二进制文件读取字节,但没有成功。 我已经尝试了很多解决方案,但没有得到结果。 结构文件:在C++中读取字节

[offset] [type]   [value]   [description] 
0000  32 bit integer 0x00000803(2051) magic number 
0004  32 bit integer 60000   number of images 
0008  32 bit integer 28    number of rows 
0012  32 bit integer 28    number of columns 
0016  unsigned byte ??    pixel 
0017  unsigned byte ??    pixel 
........ 
xxxx  unsigned byte ??    pixel 

我怎样努力(不工作):

auto myfile = fopen("t10k-images.idx3-ubyte", "r"); 
char buf[30]; 
auto x = fread(buf, 1, sizeof(int), myfile); 
+1

的部分地方说“MSB第一”是非常重要的。 –

+0

“不成功”是什么意思?我相信这应该将sizeof(int)字节读入缓冲区。读取后应检查x以确保它等于x == sizeof(int)。尝试打印出十六进制缓冲区,看看它是否正确读取它。 –

+1

我猜这个问题是endianess。如果磁盘上的“int”是大端,并且系统是小端,那么这些数字将不匹配。 –

回答

1

了解您的文件布局从哪里读取多字节数字的字节序非常重要。假设大端是总是书写格式,并假设值的确是一个32位无符号值:

uint32_t magic = 0; 
unsigned char[4] bytes; 
if (1 == fread(bytes, sizeof(bytes), 1, f)) 
{ 
    magic = (uint32_t)((bytes[0] << 24) | 
         (bytes[1] << 16) | 
         (bytes[2] << 8) | 
         bytes[3]); 
} 

注:无论读者(程序)是小端或这将工作大端。我相信我错过了至少一个在那里的演员,但希望你明白这一点。 (a)知道它们被写入的字节顺序,以及(b)逐字节读取和组装它们。

+0

在我的答案中移动每个字节之前,我将每个字节转换为'unit32_t'。不确定编译器是否会为每个班次自动提升它们。 –

+1

你不是唯一的。语言家伙知道的比我多,但我通常会像你一样做(在转变之前促进每个价值)。进行大量打字,但有效。我见过两个。请参阅[本示例](http://stackoverflow.com/questions/12765488/casting-a-char-array-to-an-integer/12765536#12765536)进行相关转换。 (我赞同你的答案,因为我同意它)。 – WhozCraig

+0

“魔法”总是0. – SevenDays

2

这是你如何从文件中读取一个uint32_t的:

auto f = fopen("", "rb"); // not the b, for binary files you need to specify 'b' 

std::uint32_t magic = 0; 
fread (&magic, sizeof(std::uint32_t), 1, f); 

希望这有助于。

+3

这不包括任何潜在的endian问题。 –

2

读取字节unsigned char

ifstream if; 

if.open("filename", ios::binary); 

if (if.fail()) 
{ 
    //error 
} 

vector<unsigned char> bytes; 

while (!if.eof()) 
{ 
    unsigned char byte; 

    if >> byte; 

    if (if.fail()) 
    { 
     //error 
     break; 
    } 

    bytes.push_back(byte); 
} 

if.close(); 

然后把多个字节为32-bit integer例如:

uint32_t number; 

number = ((static_cast<uint32_t>(byte3) << 24) 
    | (static_cast<uint32_t>(byte2) << 16) 
    | (static_cast<uint32_t>(byte1) << 8) 
    | (static_cast<uint32_t>(byte0))); 

这应包括端的问题。 int在系统上显示为B0B1B2B3B3B2B1B0并不重要,因为转换是通过位移来处理的。代码在内存中不承担任何特定的顺序。

+0

有什么不对,我得到50855936 insted 2051. – SevenDays

+0

它可能是您分配字节的顺序。我没有在这里为你设置'byte0','byte1'等。这是你必须做的事情。 –

+0

是的,我已经顺序替换字节,它的工作原理。对不起,我不能将两个答案都标记为正确。 – SevenDays

1

C++流库函数read()可用于二进制文件I/O。鉴于从链接的代码示例中,我应该像这样开头:

std::ifstream myfile("t10k-images.idx3-ubyte", std::ios::binary); 
std::uint32_t magic, numim, numro, numco; 

myfile.read(reinterpret_cast<char*>(&magic), 4); 
myfile.read(reinterpret_cast<char*>(&numim), 4); 
myfile.read(reinterpret_cast<char*>(&numro), 4); 
myfile.read(reinterpret_cast<char*>(&numco), 4); 

// Changing byte order if necessary 
//endswap(&magic); 
//endswap(&numim); 
//endswap(&numro); 
//endswap(&numco); 

if (myfile) { 
    std::cout << "Magic = " << magic << std::endl 
       << "Images = " << numim << std::endl 
       << "Rows = " << numro << std::endl 
       << "Cols = " << numco << std::endl; 
} 

如果字节顺序(字节序)予以转回,你可以写这样一个简单的反向功能:endswap()

+0

我得到类似于50855936,270991360,469762048,469762048的东西。所以这种方法不起作用。 – SevenDays

+0

@wsevendays:这与Geoff_Montee的答案相同,在这里你也得到了50855936(其他字节顺序)。尝试链接中给出的'endswap'函数! –