背景
在項目中做大文件的增量讀寫,遇到了問題:
fopen : Value too large for defined data type.
習慣性地根據這個提示查閱的有關資料顯示:
1)工具鏈太老了:海思的工具鏈我目前找不到更換的方法,也為了穩定性,不再增加新的ulibc庫
2)文件系統的 inde是 64位的:查看了 cat /proc/fs/{文件系統類型}/{設備名}/options
,發現一切正常
顯然,這樣的結果並不能讓我滿足。
Linux C/C++ 大文件讀寫下編程實現的不同
由於上文的方向不對,於是我換了個思路,直接根據需求查找: "Linux C 讀寫大文件"
了解到了有關信息:
- Linux默認環境下打開、讀、寫超過2G的文件會返回錯誤。定義
#define _FILE_OFFSET_BITS 64
宏可以突破這個限制,對read/write和fread/fwrite同時有效。(注意必須定義在<stdio.h>之前。至此,open文件算是沒有問題了)
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
細心的讀者肯定注意到了,還有2個宏,這2個宏是與 fpos_t 有關的;而這個 fpos_t 與 操作文件偏移量有關。
傳統 偏移操作 : fseek()
+ ftell()
fseek(fp,0,SEEK_END);
length = ftell(fp);
fseek( fp, 0, SEEK_SET);
printf("%ld", length );
處理大文件時,ftell 的返回值有問題:要么是-1,要么是_length數據類型的最大值,總之都是不對的。
而正確的方式應該是 使用 : fseek()
+ fgetpos()
或fsetpos()
解決辦法是:
fpos_t pos;
fseek(fp,0,SEEK_END);
fgetpos(fp,&pos);
fseek( fp, 0, SEEK_SET);
fseek、ftell() 與 fgetpos()、fsetpos()
我們都知道ftell與fseek一起使用;而fsetpos與fgetpos也要結合fseek使用。
ftell與fseek返回的是長整數,而后面兩個則是返回一個新類型:fpos_t
ftell() 用長整型表示文件內的偏移 (位置), 因此, 偏移量被 限制在 20 億 (231-1) 以內。
而新的 fgetpos() 和 fsetpos() 函數使用 了一個特殊的類型定義 fpos_t 來表示偏移量 (這個類型的值的內容與 _LARGEFILE_SOURCE、_LARGEFILE64_SOURCE 宏有關)
因此, fgetpos() 和 fsetpos 可以表示任意大小的文件偏移,fgetpos() 和 gsetpos() 也可以用來記錄多字節流式文件的狀態。
基於 mmap 的 大文件讀寫
我在查閱資料的時候,也發現 可以通過 mmap 的方式來操作大文件(以前讀寫FrameBuffer的時候就用到了這種方式)