我正在使用以下代码在 Windows 上的 MSVC 中打开一个大型 (5.1GB) 二进制文件。机器有足够的内存。问题是长度被检索为零。但是,当我将 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. */
它不是文件权限或任何东西,它们很好。
最佳答案
如果分配 5.1 GB,则最好确保已将代码编译为 64 位并在 64 位 Windows 版本上运行。否则,内存address space is limited在 32 位 Windows 和 4 GB with 32 bits code on a 64 bits Windows 上最大 3 GB .
顺便说一下,ftell()
返回一个带符号的 long
。您必须检查这里没有错误(例如,如果操作系统允许更大的文件大小则发生溢出),因此该值不是 -1。
编辑:
请注意 with MSVC, long
will currently be即使编译为 64 位,也是 32 位数字。这意味着如果文件大小低于 2GB(因为符号),ftell()
将为您提供有意义的结果。
您可以使用非可移植操作系统特定的 WinAPI 函数 GetFileSizeEx()
以带符号的 64 位数字获取大文件的大小。
malloc()
接受一个 size_t
,它是一个 unsigned 64 bit number .所以在这一边你是安全的。
另一种方法是使用 file mapping .
第二次编辑
我查看了您对收到的尺寸值(value)的编辑,这与我的预期不同。我可以在我的系统上重现错误,并得到一个不为空的大小,但它是一个比文件大得多的数字。
查看this CERT security recommendation ,似乎 fseek()
标准与 SEEK_END
结合提供的保证是不充分的,这使它成为一种非常不安全的方法。
让我们重申一下:获取大小的最安全方法是使用 native 操作系统函数,即 Windows 上的 GetFileSizeEx()
。在 64 位 Windows 上有一个解决方法:使用 _fseeki64()
和 _ftelli64()
:
...
if (_fseeki64(pFile, 0, SEEK_END)) {
fputs("File seek error", stderr);
return (1);
}
lSize = _ftelli64(pFile); // RETURNS EXACT SIZE
...
这工作得很好(最初的问题似乎与返回类型不够大有关)。但是请记住,这是一种变通方法,我担心可能存在其他错误情况可能导致 CERT 报告的漏洞。
关于c++ - 可以打开小的 ASCII 文件,但不能打开大的二进制文件吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39677947/