1. 程式人生 > >C++ 讀取BIN檔案的一些問題

C++ 讀取BIN檔案的一些問題

程式要求讀取一個ARM的BIN檔案,需要獲取每一個位元組,寫了一個函式測試一下:

檔案:


由於不熟悉,弄出了很多問題。相關問題如下:

1 BIN檔案

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

BIN檔案不以ASCII碼存放資料,它將記憶體中資料儲存形式不加轉換地傳送到磁碟檔案,因此它又稱為記憶體資料的映像檔案。檔案中的資訊不是字元資料,而是位元組中的二進位制形式的資訊,因此它又稱為位元組檔案。

文字工具開啟一個檔案,如記事本,首先讀取檔案物理上對應的二進位制位元流,再按使用者選擇的解碼方式來解釋這個流,再顯示解釋結果。如果記事本無論開啟什麼檔案都按某種特定編碼(如ASCII碼),就可能出現亂碼。

如上面的test.bin檔案,用EmEditor直接開啟,(其編碼:GB2312),會提示某些字元無法用指定的編碼進行轉換。想要像上面這張圖方便地檢視16進位制,就要選擇以二進位制方式開啟(16進位制試圖),如果選擇ASCII檢視,也是亂碼。

不管你怎麼樣,儲存的都還是那個東西。我們看到的字元並不代表儲存的是一個字元。如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會出現錯誤。

每個數對應的是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了)。

如此修改過後,結果正確了,如果不注意細節,就會有一些很繞人的錯誤: