1. 程式人生 > >C、C++一次將整個檔案讀入記憶體

C、C++一次將整個檔案讀入記憶體

@1.問題描述:

        C和C++的初學者經常採用一行一行讀入檔案的辦法對檔案資料進行處理。但是經常會有一些情況需要將一個檔案整體一次讀入記憶體處理。而C和C++庫中並沒有提供直接一次讀入檔案全部資料的函式。

@2.解決方法:

        目前給出C和C++的解決方案,下面兩個程式只是用於演示,不過這些程式碼已經很容易改寫成想要的函數了。

        解決這個問題的思路是:

        1.由於要將檔案完整讀入,所以必須使用二進位制方式開啟(若文字方式開啟,檔案流中會把一些非字元的資料過濾掉,我們將讀取不到那些內容)。

        2.開啟檔案後,我們首先獲取檔案的大小,然後在記憶體中分配足夠的空間,再把檔案拷貝到記憶體空間中。之後使用記憶體空間進行資料處理,演示程式中沒有真正的處理,我們只是簡單將其輸出。

@3.程式碼:

C實現

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main ()  
  4. {  
  5.     FILE * pFile;  
  6.     long lSize;  
  7.     char * buffer;  
  8.     size_t result;  
  9.     /* 若要一個byte不漏地讀入整個檔案,只能採用二進位制方式開啟 */
  10.     pFile = fopen ("test.txt""rb" );  
  11.     if (pFile==NULL)  
  12.     {  
  13.         fputs ("File error"
    ,stderr);  
  14.         exit (1);  
  15.     }  
  16.     /* 獲取檔案大小 */
  17.     fseek (pFile , 0 , SEEK_END);  
  18.     lSize = ftell (pFile);  
  19.     rewind (pFile);  
  20.     /* 分配記憶體儲存整個檔案 */
  21.     buffer = (char*) malloc (sizeof(char)*lSize);  
  22.     if (buffer == NULL)  
  23.     {  
  24.         fputs ("Memory error",stderr);   
  25.         exit (2);  
  26.     }  
  27.     /* 將檔案拷貝到buffer中 */
  28.     result = fread (buffer,1,lSize,pFile);  
  29.     if (result != lSize)  
  30.     {  
  31.         fputs ("Reading error",stderr);  
  32.         exit (3);  
  33.     }  
  34.     /* 現在整個檔案已經在buffer中,可由標準輸出列印內容 */
  35.     printf("%s", buffer);   
  36.     /* 結束演示,關閉檔案並釋放記憶體 */
  37.     fclose (pFile);  
  38.     free (buffer);  
  39.     return 0;  
  40. }  

C++實現

  1. #include <iostream>
  2. #include <fstream>
  3. usingnamespace std;  
  4. int main () {  
  5.   filebuf *pbuf;  
  6.   ifstream filestr;  
  7.   long size;  
  8.   char * buffer;  
  9.   // 要讀入整個檔案,必須採用二進位制開啟 
  10.   filestr.open ("test.txt", ios::binary);  
  11.   // 獲取filestr對應buffer物件的指標 
  12.   pbuf=filestr.rdbuf();  
  13.   // 呼叫buffer物件方法獲取檔案大小
  14.   size=pbuf->pubseekoff (0,ios::end,ios::in);  
  15.   pbuf->pubseekpos (0,ios::in);  
  16.   // 分配記憶體空間
  17.   buffer=newchar[size];  
  18.   // 獲取檔案內容
  19.   pbuf->sgetn (buffer,size);  
  20.   filestr.close();  
  21.   // 輸出到標準輸出
  22.   cout.write (buffer,size);  
  23.   delete []buffer;  
  24.   return 0;  
  25. }  

@4.注意的問題:

在這個演示程式中,如果採用文字方式開啟會如何呢?即把C實現中的檔案開啟改為pFile = fopen ("test.txt","r" ),C++中的檔案開啟改為filestr.open ("test.txt")

雖然這個用於測試的檔案本身是一個文字檔案,文字內容為:

test.txt

  1. abcdefghijklm  
  2. abcdefghijklm  
  3. ppdsbd  

但是如果採用文字模式開啟仍會出現問題,測試中的“C實現”程式碼的程式會輸出:

  1. Reading error  

        原因是有一些字元被檔案流處理掉了,這造成fread函式講到的字元數少於檔案大小lSize,返回值result不等於lSize於是程式輸出Reading error後退出了。

        同樣的情況在C++實現的程式碼中也有,但是C++程式並沒有退出,但它的輸出結果不對,內容如下(僅為本機測試結果,因時因機器而異)

  1. abcdefghijklm  
  2. abcdefghijklm  
  3. ppdsbdes\M  
        很明顯末尾多出了"es\M"四個無效字元,很明顯檔案的末尾的字串終止符('\0')被處理掉了,它並沒有被寫入buffer中,以致輸出時多輸出了四個無效字元。