C++二進制文件的讀取

今天在作項目時聯想到了這兩個問題,因此實際編程測試了一下,有一些新的收穫:ios

  <1> 我一直覺得本身很熟悉如何使用C/C++中的二進制文件,可今天測試的時候忽然發現程序生成的二進制文件和文本文件同樣。好比:編程

  FILE* fp = fopen("binary","wb");app

  //FILE* fp = fopen("character.txt","w");函數

  fprintf(fp,"count is %d",250);測試

  上述代碼一個使用的是text file mode,一個是binary file mode,但結果生成的二進制文件中保存的仍然是ASCII碼,直接用記事本就能夠打開查看。要說區別,主要是換行符的區別,binary file的換行符爲<LF>,而text file的換行符爲<CR><LF>,僅此而已,我就想怎麼回事啊,我明明是用二進制模式打開的文件呀,怎麼裏面直接保存的仍是ASCII碼?也就是說保存125這個數字仍是會佔用3個字節,而不是我想象中那樣只佔一個字節!spa

  後來我就換用C++,結果仍是同樣,代碼以下:指針

  ofstream fs("binary",ios::binary);blog

  //ofstream fs("character.txt");get

  int i = 32765;it

  fs<<i<<endl;

  //fs.write((char*)&i,2);

  fs.close();

  不管以二進制文件模式打開仍是以文本模式打開,文件中都是保存着文本!彷佛C/C++中的binary模式不起做用!?!

  後來查閱資料才知道:要想在C/C++中將數據以二進制形式文件輸出,與你打開文件時的模式沒有關係,關鍵是取決於你調用哪一個函數往文件裏寫東西!!只有使用fwrite和fs.write()函數才能以二進制形式輸出到文件中,調用puts、fprintf、<<等函數輸出的都是ASCII文本,尤爲須要注意的是相似於上面代碼段中那樣,在C++中,即便你用fs<<i<<endl語句來輸出一個整數,輸出到二進制文件中的仍然是文本格式!<< operator在輸出以前會自動給你進行轉換,把一個整數值轉換成一位一位的數字字符!!並且我後來試過了,即便我以文本模式打開一個文件,假如我用fwrite函數輸出的話,文件中仍然是二進制格式,呵呵,說明在輸出數據到文件時,的確與打開文件的模式沒有關係,只與調用的輸出函數有關!!

  此外,要注意,你不能用>>來讀取以二進制文件格式存儲的整數!(注:中午我試過了,不行!這再次證實>>只能讀入文本格式的數字)

  (補註:11:47am   我後來又想,全部上面的這些東西能夠歸結成一句話:你以什麼模式打開文件根本不重要,由於你既改變不了文件自己的內容,也改變不了C/C++中系統函數的工做方式,因此在編程的時候,你只要關心這個文件裏的數據內容自己是二進制格式仍是文本格式就行了!若是內容是文本格式的,你就調用文本格式那一套函數,好比puts,gets,fscanf,fprintf,<<,>>等,若是內容是二進制格式的,你就調用二進制格式那一套函數,好比fread,fwrite,ifstream.read(),ofstream.write()等。 只要保持文件內容與處理函數相對應相一致就能夠了,別管它用什麼模式打開文件!! 假如你用<<向一個二進制文件中輸入一個整數,那麼其實裏面保存的是文本格式的數據,那麼你就照樣能夠以二進制模式打開它,而後用>>來讀取這個整數。相反,若是你的二進制文件裏面是一個以二進制形式保存的整數,那你確定不能用>>來讀取裏面的整數了!!

  <2>關於字節序的問題,我想用一張圖來表示就足夠了:

  今天終於弄明白怎樣使用C++讀寫二進制文件了。

  要讀取文件必須包含<fstream>頭文件,這裏包含了C++讀寫文件的方法。

  可使用fstream類,這個類能夠對文件進行讀寫操做。

 

一、打開文件。

  打開文件能夠有兩種方式,第一種可使用fstream類的構造函數。

  fstream file("test.dat",ios_base::in|ios_base::out|ios_base::app);

  另一種方法就是使用open函數。

  fstream file;

  file.open("test.dat",ios_base::in|ios_base::out|ios_base::app);

  這樣就能夠打開一個可讀寫的文件了。若是文件不存在的話,就會建立一個新文件而且以讀寫方式打開。

  這裏須要說明一點,若是文件不存在的話,open函數中第二個參數必須包含ios_base::out|ios_base::app,

  不然就不能正確建立文件。

  二、寫文件。

  先進性寫文件的操做不然讀一個空文件是沒有意義的。

  既然是寫二進制文件能夠向文件中寫入一個整形值。寫二進制字符只能使用write函數。

  可是write函數的原形是write(const char * ch, int size)。第一個參數是char *類型,因此須要把將要寫入

  文件的int類型轉換成char *類型。這裏的轉換困擾了我好幾天,不過終於弄明白了。代碼以下。

  int temp;

  file.write((char *)(&temp),sizeof(temp));

  三、讀文件。

  能夠寫文件了,讀文件就好辦多了。讀文件須要用到read函數。其參數和write大體相同,read(const char * ch, int size)。

  要把內容讀到int類型變量中一樣涉及到一個類型轉換的問題。和寫文件同樣。

  int readInt;

  file.read((char *)(&readInt),sizeof(readInt));

  這樣文件中的int值就讀入到int型變量readInt中了。

  四、文件指針。

  在文件的讀寫過程當中每每須要對文件進行選擇性讀取。因此須要進行文件指針的移動。這是須要用到seekg和seekp函數。

  在fstream類中有兩個文件指針,一個是讀取文件的指針,一個是寫文件的指針分別用tellg和tellp文件來取得指針的位置。

  一樣seekg和seekp兩個函數分別是對這兩個指針進行移動的函數。這兩個函數的參數都是同樣的。

  先對幾個枚舉類型進行一下說明:

  ios_base::beg ——文件開始位置

  ios_base::cur ——文件當前位置

  ios_base::end ——文件末尾位置

  下面以seekg爲例說明一下指針移動的方法:

  file.seekg(3)   ——指針移動到第三個字符的位置

  file.seekg(ios_base::beg) ——指針移動到文件開頭

  file.seekg(ios_base::end) ——指針移動到文件末尾

  file.seekg(-3,ios_base::cur) ——指針當前位置向前移動三個字符

  file.seekg(3,ios_base::cur) ——指針當前位置向後移動三個字符

  file.seekg(3,file.tellg()) ——指針當前位置向後移動三個字符

  file.seekg(file.tellg()+3) ——指針當前位置向後移動三個字符

  五、對文件操做完畢後別忘了關閉文件。

  file.close();

  以上5個步驟就完成了對文件的讀寫操做。文本文件的操做是相同的,比二進制文件還要簡單。