我查看了许多关于编译代码以使其读取/写入超过 32 位文件偏移允许的 4GB 最大值的文件的答案。我找到的任何“简单”解决方案都没有成功。
要点是,我在一台小型笔记本电脑(32 位 Intel 架构)上运行 Ubuntu Server 11.10。我试图读取一个大小为 343868522737 字节(0x50102940f1)的 unicode 文件。Ubuntu 机器一直认为它要小得多(0x102940f1),结果发现它只是真正 64 位大小文件的低 32 位。
我写了一个小程序,在 MacOS 和 Ubuntu 机器上编译过。Mac 似乎运行正常,但 Ubuntu 机器则不行。
下面是一个小程序。虽然我注释掉了一个代码块,但这实际上只对 Mac 是必要的。Ubuntu 环境将很好地编译这两个代码块 - 并为这两个代码块生成完全相同的响应。
// Necessary for Ubuntu build?
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
//#include <features.h>
// finish Ubuntu
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>
// Ubuntu version
off64_t fileMaxLen(FILE* fin) {
off64_t fmaxlen = 0;
if( (fin!=NULL) && (fseeko64(fin,0,SEEK_END) == 0) ) {
fmaxlen = ftello64(fin);
fprintf(stdout,"fileMaxLen(): file length is: %#lx \n",(long unsigned int)fmaxlen);
fseeko64(fin,0,SEEK_SET);
}
}
// Mac OS version
//off_t fileMaxLen(FILE* fin) {
// off_t fmaxlen = 0;
// if( (fin!=NULL) && (fseeko(fin,0,SEEK_END) == 0) ) {
// fmaxlen = ftello(fin);
// fprintf(stdout,"fileMaxLen(): file length is: %#lx \n",(long unsigned int)fmaxlen);
// fseeko(fin,0,SEEK_SET);
// }
//}
main(int argc, char* argv[]) {
char fname[255];
char *locale;
FILE* f = NULL;
locale = setlocale(LC_ALL, "");
if( argc>=2 ) {
// get the file for segmenting
memset(fname, '\0', 255);
sprintf(fname,"%s",argv[1]);
fprintf(stdout,"Opening: %s\n",fname);
f = fopen(fname,"r");
fileMaxLen(f);
fprintf(stdout,"Done!\n");
} else {
fprintf(stdout,"Need a filename\n");
}
}
将代码片段保存为file_test.c,然后编译就非常简单了。
gcc文件_测试.c
然后运行 a.out
有什么建议可以让这段代码识别 32 位边界以外的文件吗?目前我完全不知所措。
答案1
根据这,在32位Unix上的大小long unsigned int
是4个字节-是否可以在将fmaxlen转换为(long unsigned int)时修剪该值?
答案2
您可以找到有关使用 控制此行为的宏的文档man feature_test_macros
。
从该文档中,您只需要设置_FILE_OFFSET_BITS
为64
。这应该将off_t
和函数(如)fseeko
重新定义ftello
为 64 位安全版本(这在 64 位系统上是无操作,并将符号重定向到32 位系统上的后缀版本)。这比直接64
使用后缀函数更好。64
正如 Sergey 所说,将值转换off_t
为long unsigned int
会丢失 32 位系统上的信息。我认为 没有 的标准printf
格式代码off_t
,因此最好将值转换为unsigned long long int
并使用%#llx
作为格式代码。这应该不会对两个字长发出警告,也不会丢失信息。