C++ 读取BIN文件的一些问题

程序要求读取一个ARM的BIN文件,需要获取每一个字节,写了一个函数测试一下:

文件: C++ 读取BIN文件的一些问题


由于不熟悉,弄出了很多问题。相关问题如下:

1 BIN文件

(大部分见https://www.cnblogs.com/pengwangguoyh/articles/3223072.html)

BIN文件不以ASCII码存放数据,它将内存中数据存储形式不加转换地传送到磁盘文件,因此它又称为内存数据的映像文件。文件中的信息不是字符数据,而是字节中的二进制形式的信息,因此它又称为字节文件。

文本工具打开一个文件,如记事本,首先读取文件物理上对应的二进制比特流,再按用户选择的解码方式来解释这个流,再显示解释结果。如果记事本无论打开什么文件都按某种特定编码(如ASCII码),就可能出现乱码。

如上面的test.bin文件,用EmEditor直接打开,(其编码:GB2312),会提示某些字符无法用指定的编码进行转换。想要像上面这张图方便地查看16进制,就要选择以二进制方式打开(16进制试图),如果选择ASCII视图,也是乱码。

C++ 读取BIN文件的一些问题

不管你怎么样,存储的都还是那个东西。我们看到的字符并不代表存储的是一个字符。如01000000按ASCII码解码,则对应是A,记事本可以显示A,但是也有可能只是一个4字节int数据的四分之一。不管是二进制文件,还是文本文件,都是一连串的0和1,但是打开方式不同,对于这些0和1的处理也就不同。如果按照文本方式打开,在打开的时候会进行translate,将每个字节转换成ASCII码,而以按照二进制方式打开的话,则不会进行任何的translate;二进制文件是按二进制的编码方式来存放文件的。例如,数5678的存储形式为:00010110 00101110 只占二个字节。二进制文件虽然也可在屏幕上显示,但其内容无法读懂。C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。因此也把这种文件称作“流式文件”。

2 C++ 读取

C++打开文件,以什么模式打开不重要,既改变不了文件本身的内容,也改变不了C/C++中系统函数的工作方式,所以只要关心这个文件里的数据内容本身是二进制格式还是文本格式,如果内容是文本格式的,就调用文本格式那一套函数,比如puts,gets,fscanf,fprintf,<<,>>等,如果内容是二进制格式的,你就调用二进制格式那一套函数,比如fread,fwrite,ifstream.read(),ofstream.write()等。 只要保持文件内容与处理函数相对应相一致。

这个问题暂时没有遇到,因为打开时都指明了:ios::binary,调用的也是read(),先记下来以防以后出错。

C++读取BIN文件,可以用ifstream的read()。

原型: read( char *buffer, streamsize number );

有的文章里第一个参数是unsigned char* ,但是vs2015里看到的是char *。

buffer即指向缓冲区指针,number即读取字节数。


3 类型的转换

在类型的转换这上面绕了很久:

首先程序要求,我要用unsigned int类型存储每个字节,假设是k,read文件的第一个参数是char *,也就是说读取的一个字节的数据类型是char,假设用x存储,然而x直接赋值给k会出现错误。

C++ 读取BIN文件的一些问题

每个数对应的是E3 A0 00 A0,(小端模式),

E3即1110 0011,扩展32位的话 1111 1111 1110 0011(我们看到的,存储的就是补码)

正好就是4294967267.

如果x是unsigned char,赋值给k就不会出错。

但是在read函数参数里要进行类型转换,即改成read((char*)&x, 1))

&x是(unsigned char *)强制指针类型转换成(char *),都是8位,对x没有区别,指针强制类型转换仅是将这个地址单元里存储的内容按不同的类型进行变量解释和读取,但如果这两个指针指向数据类型字节数不同,数据就发生变化了。(如x:E3 还是1110 0011(不管解释成char 还是 unsigned char )但如果转换成 int类型 就会扩展x了)。

如此修改过后,结果正确了,如果不注意细节,就会有一些很绕人的错误:

C++ 读取BIN文件的一些问题