如何:C 中的跨操作系统大文件 IO?
Posted
技术标签:
【中文标题】如何:C 中的跨操作系统大文件 IO?【英文标题】:HOWTO: Cross-Operating-System Large File IO in C? 【发布时间】:2014-04-23 23:28:26 【问题描述】:简而言之: C 中的跨操作系统、大文件支持非常可怕。
目标:我正在尝试使用“一种方式”(最有可能基于宏)来允许 32 位和 64 位支持大文件。理想情况下,使用 typedef、#ifdef、#(n)defined 等,宏包装器可以允许以 #include 库或一组已定义宏的形式支持基本的大文件。
研究: POSIX 的文件操作在 32 位和 64 位 IO 的 BSD/Mac/Linux 上表现出色,文件大于典型的 2^31 大小,但即使在 Windows 上使用 clang 或 mingw由于 M$ 对 POSIX 的愚蠢实现,我无法利用这些调用(如果这就是我们想要调用的......)。我倾向于在 Windows 上使用 CreateFile()、ReadFile()、WriteFile(),但这在方法和数据类型方面与 POSIX 的 open()/read()/write()/close()/etc 完全不同用过。
问题:在敲了敲键盘和几本教科书之后,我决定对你们所有人进行投票,看看:你们是如何完成跨操作系统文件的支持大文件的 I/O?
附:我有研究链接:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb540534(v=vs.85).aspx Portable way to get file size in C/C++ How can I portably turn on large file support? http://mingw-users.1079350.n2.nabble.com/not-obvious-how-to-compile-programs-for-large-files-td5699144.html http://www.viva64.com/en/l/full/ https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/64bitPorting/HighLevelAPIs/HighLevelAPIs.html https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+Do+not+use+fseek%28%29+and+ftell%28%29+to+compute+the+size+of+a+regular+file https://www.securecoding.cert.org/confluence/display/c/FIO03-C.+Do+not+make+assumptions+about+fopen%28%29+and+file+creation https://en.wikipedia.org/wiki/Large_file_support【问题讨论】:
【参考方案1】:看来,你需要一个不同版本的mingw:
http://mingw-w64.sourceforge.net/
w64 变体甚至在 32b 窗口上也支持 linux 兼容的大文件。
【讨论】:
【参考方案2】:尽管我们都喜欢讨厌 M$ 的糟糕标准一致性,但这实际上是 ISO C 委员会的错。最初他们将 size_t 用于所有文件参数,但 size_t 是基于 ALU/内存架构而不是基于 OS 文件处理能力选择的。当每个人都切换到 64 位 CPU 时,MS 坚持使用 32 位长度,他们完全可以这样做并且仍然符合要求,但现在他们的文件比他们最大的算术类型大。
请注意,这最终在 C99 中得到解决,但 MSVC C99 支持基本上不存在。
然而,在内部,它们确实使用 64 位指针来跟踪您在文件中的位置。问题是由于不幸的 cstdlib API,您不能对大于 32 位的任何内容使用“fseek”或“ftell”。
为了证明 Windows 确实使用了 64 位文件指针,这段代码在使用 MSVC++ 编译时实际上会按预期工作,并会在您的硬盘驱动器上生成一个 40GB 的文件(无符号长整数为 32 位)。
#include <stdio.h>
int main(int argc, char **argv)
FILE *my_file;
unsigned long i, j;
my_file = fopen("bigfile.bin", "wb");
for(i = 0; i < 10; i++)
for(j = 0; j < (1024 * 1024 * 1024); j++)
fwrite(&j, sizeof(j), 1, my_file);
fclose(my_file);
return 0;
那么这对您有什么帮助?嗯,MS 提供了自己的非标准 API,允许 64 位 fseek() 和 ftell()
https://msdn.microsoft.com/en-us/library/75yw9bf3.aspx
不过,您实际上可以使用常规 fseek() 以增量方式移动文件指针...基本上如果您这样做:
fseek(my_file, 0, SEEK_SET);
for(i = 0; i < 10; i++)
fseek(my_file, (1024 * 1024 * 1024), SEEK_CUR);
它将有效地将文件指针移动到 10GB 标记。
虽然使用 ftell(),但如果不使用 MS API,您可能会被搞砸。
TL;DR - fopen()、fread() 和 fwrite() 可以在大于 2GB 的大文件的 MSVC 上工作,但 ftell() 和 fseek() 不能,因为 API 设计不正确。
【讨论】:
【参考方案3】:你不是完全没有Windows中的选项:
_fseeki64
_ftelli64
…
在 Linux 中,您可以使用 -D_FILE_OFFSET_BITS=64
(#define _FILE_OFFSET_BITS 64
可能工作,不确定)和 fseeko
/ ftello
。许多系统还具有fseeko64
和ftello64
),无论#define
如何,它们都可以正常工作。
【讨论】:
以上是关于如何:C 中的跨操作系统大文件 IO?的主要内容,如果未能解决你的问题,请参考以下文章