這是因為 Linux 的系統內部處理檔案時用的指標定義為 long,而 long 在 32 位元的系統上的大小為 32 位元,因此最大只能支援 2^31-1 = 2,147,483,647 bits 等於是 2GB 扣掉 1 bite 的檔案大小。
64 位元的系統 (例如 AMD64 或 IA64) 則因為 long 定義成 64 位元,所以不會有問題。因此在 32 位元的 Linux 上面,程式需要作一些額外處理才能正確寫超過 2GB 的檔案。
首先我們先準備一個簡單的測試檔 test.cpp,大致上就是透過 fprintf 每一次輸出 3 bits 的資料,然後迴圈的個數是 1 Giga 次,也就是我們希望可以輸出 3 bits * 1 Giga = 3.0 Giga 的資料量,用這個來測試我們是否可以成功突破 linux 上 2.0 G 的檔案大小限制。
#includeconst int filesize = 1024 * 1024 * 1024; //1 Giga int main() { FILE* fp = fopen("log", "w"); for (int i = 0; i < filesize; i++) { fprintf(fp, "%s", "12\n"); //3 bits } fclose(fp); }
接著試著編譯和執行。觀察一下輸出log檔的檔案大小,顯示為 2.0G,其實就是2,147,483,647 bits。但是我們的測試檔明明就是想要輸出 3.0G 的檔案啊,剩下的 1.0G 還真得給他不見了。
g++ test.cpp ./a.out ls -lh -rw-r--r-- 1 root root 2.0G 2012-09-12 09:34 log
一個比較簡單的解決方法就是在編譯的時候加入-D_FILE_OFFSET_BITS=64,也就是檔內部操作的時候,是用 64 bits 的指標,就不會有檔案大小的限制了。
g++ -D_FILE_OFFSET_BITS=64 test.cpp ./a.out ls -lh -rw-r--r-- 1 root root 3.0G 2012-09-12 09:49 log
不過處理這些大檔案的時候,除了編譯程式時的參數不同外,有些函數的使用上也要作一些調整,例如 fseek() 與 ftell() 這兩個原本使用到 long integer 當作 offset 的函數,只要系統是 32 位元,都需要改為使用 off_t 的版本:
Reference
- 激情、专注、坚持、思考 - LINUX下写大文件
- Dada's Blog - Bypass the 2GB file size limit on 32-bit Linux
沒有留言:
張貼留言