可以打开小的ASCII文件,但不能打开大的二进制文件吗?

时间:2016-09-24 15:20:55

标签: c++ c file c++11 large-files

我使用以下代码在Windows上的MSVC中打开一个大型(5.1GB)二进制文件。机器有足够的RAM。问题是长度被检索为零。但是,当我将file_path更改为较小的ASCII文件时,代码可以正常工作。

为什么我无法加载大型二进制文件?我更喜欢这种方法,因为我想要一个指向文件内容的指针。

FILE * pFile;
uint64_t lSize;
char * buffer;
size_t result;

pFile = fopen(file_path, "rb");
if (pFile == NULL) { 
    fputs("File error", stderr); exit(1); 
}

// obtain file size:
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);                                // RETURNS ZERO
rewind(pFile);

// allocate memory to contain the whole file:
buffer = (char*)malloc(sizeof(char)*lSize);
if (buffer == NULL) {
    fputs("Memory error", stderr); exit(2); 
}

// copy the file into the buffer:
result = fread(buffer, 1, lSize, pFile);             // RETURNS ZERO TOO
if (result != lSize) {                               // THIS FAILS
    fputs("Reading error", stderr); exit(3); 
}

/* the whole file is now loaded in the memory buffer. */

它不是文件权限或任何东西,它们没问题。

2 个答案:

答案 0 :(得分:2)

如果你分配5,1 GB,你最好确保用64位编译代码并在64位Windows版本上运行它。哦,在32位Windows和address space is limited上,内存4 GB with 32 bits code on a 64 bits Windows到最大3 GB。

顺便说一下,ftell()会返回已签名的long。您必须检查此处是否存在错误(例如,如果操作系统允许更大的文件大小,则会出现溢出),因此该值不是-1。

修改:

注意with MSVC, long will currently be即使编译为64位也是32位数。这意味着ftell()如果文件大小低于2GB(因为符号),将给你一个有意义的结果。

您可以使用非便携式操作系统特定的WinAPI函数GetFileSizeEx()来获取带符号64位数的大型文件的大小。

malloc()需要size_t unsigned 64 bit number。所以在这方面,你是安全的。

另一种方法是使用file mapping

第二次修改

我查看了您对大小收到的值的编辑,这与我的预期不同。我可以在我的系统上重现错误,并获得一个非空的大小,但它是一个比文件大得多的数字。

查看this CERT security recommendation,似乎fseek()标准与SEEK_END组合提供的保证效率不高,并且这种做法非常不安全。

让我们重复一遍:获得大小的最简单方法是在Windows上使用本机操作系统功能,即GetFileSizeEx()。在64位窗口上有解决方法:使用_fseeki64()_ftelli64()

...
if (_fseeki64(pFile, 0, SEEK_END)) {
    fputs("File seek error", stderr); 
    return (1);
}
lSize = _ftelli64(pFile);                            // RETURNS EXACT SIZE
...

这非常有效(最初的问题似乎与返回类型相关联,但返回类型不够大)。但请记住,这是一种解决方法,我担心可能存在其他可能导致CERT报告的漏洞的错误情况。

答案 1 :(得分:1)

数据类型long太小,无法表示文件大小。使用stat()方法(或Windows特定的替代GetFileAttributes)来读取文件大小。