对大文件的便携式支持
Portable support for large files
我看了看
- 这
- 而这个
- 而这个
我仍然不知道如何以便携式方式了解大于 4 GB 的文件大小。
值得注意的是,合并一些答案在Cygwin编译时失败了,而其他答案在Linux上失败了。
事实证明,有相当多的函数由各种标准定义:
-
fseek
/ftell
它由 ANSI 标准库定义。它几乎无处不在。它保证仅适用于 32 位整数,但不是必需的(这意味着您可能会获得对开箱即用的大文件的支持)。
-
fseeko
/ftello
这是由POSIX标准定义的。在许多平台上,根据
_FILE_OFFSET_BITS
的值,off_t
被定义为off64_t
,fseeko
定义为_FILE_OFFSET_BITS=64
fseeko64
。 -
fseeko64
/ftello64
这是 64 位等效于
fseeko
和ftello
。我在任何标准中都找不到这方面的信息。天鹅座不一致
虽然它符合 POSIX,但无论我在 Cygwin 下定义什么,我都无法编译
fseeko
,除非我使用--std=gnu++11
这显然是无稽之谈,因为它是 POSIX 的一部分而不是 GNU 扩展。那么什么给了呢?根据这个讨论:64 位文件访问是自然的 Cygwin 的文件访问类型。 off_t为 8 个字节。 没有 foo64 函数因此而起作用。 只需使用fopen和朋友,你就会得到64 免费访问位文件。
这意味着在POSIX平台上
#ifdef
cygwin。 -
_fseeki64
/_ftelli64
它们由Microsoft Visual C++ 定义,并且专门用于其编译器。显然,它不支持上面列表中的任何其他内容(除了
fseek
),因此您将需要#ifdef
s。编辑:我实际上建议不要使用它们,我不是唯一一个这么认为的人。我从字面上经历了以下经历:
- 在二进制模式下
wfopen
文件 -
fwrite
10 字节的价值 -
_ftelli64
职位 - 它返回 12 个字节而不是 10 个字节
看起来这已经坏得可怕了。
- 在二进制模式下
-
lseek
和lseek64
由 POSIX 定义,这些描述符将与使用
unistd.h
open()
而不是FILE*
结构打开的整数文件描述符一起使用。这些与Windows不兼容。同样,它们使用off_t
数据类型。 -
_lseek
,_lseeki64
这是Windows相当于
lseek
/lseek64
。奇怪的是,_lseeki64
不使用off_t
而是使用__int64
,所以你知道它会处理大文件。整洁。 -
fsetpos
/fgetpos
虽然这些实际上是非常便携的,但它们几乎无法使用,因为它们在不透明的结构而不是整数偏移量上运行,这意味着您可以添加或减去它们,甚至可以导航到通过除
fgetpos
以外的任何方式获得的文件中的某个位置。
结论
因此,为了使您的程序可移植,根据平台的不同,您应该使用:
-
fseeko
(POSIX) + 在 POSIX 上定义_FILE_OFFSET_BITS=64
-
fseek
用于 Cygwin 和默认实现 -
_lseeki64
适用于 Windows - 或者,如果您设法绕过它 -_fseeki64
.
使用_ftelli64
的示例:
int64_t portable_ftell(FILE *a)
{
#ifdef __CYGWIN__
return ftell(a);
#elif defined (_WIN32)
return _ftelli64(a);
#else
return ftello(a);
#endif
}
实际上,与其检查对我来说总是脆弱#ifdef
,不如检查函数是否使用构建系统进行编译,并相应地定义自己的常量,例如HAVE_FTELLO64
。
请注意,如果您确实决定使用 lseek
/_lseeki64
系列和数字文件描述符而不是FILE*
结构,您应该注意 open
/fopen
之间的以下差异:
-
open
不使用缓冲,fopen
使用缓冲。缓冲越少意味着性能越差。 open
无法对文本文件执行换行符转换,fopen
可以。这个问题中有更多详细信息。
引用:
- http://www.lix.polytechnique.fr/~liberti/public/computing/prog/c/C/FUNCTIONS/funcref.htm#stdio
- http://pubs.opengroup.org/onlinepubs/9699919799/functions/fseek.html
- http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
- http://pubs.opengroup.org/onlinepubs/009695399/functions/lseek.html
- http://man7.org/linux/man-pages/man2/lseek.2.html
- https://msdn.microsoft.com/en-us/library/75yw9bf3.aspx
- http://www.cplusplus.com/reference/cstdio/fgetpos/
- http://pubs.opengroup.org/onlinepubs/009695399/functions/fgetpos.html
- 编译时未启用intel oneApi CUDA支持
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 使用CMake检测支持的C++标准
- 为什么istream不支持右值提取
- 当我编译webrtc服务器时,Windows上只支持clang-cl
- 扩展光电二极管探测器以支持多个传感器
- MSVC是否支持C++11样式的属性而不是__declspec
- 在使用GPU支持编译Tensorflow时,会遇到CUDA_TOOLKIT_PATH未绑定变量
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- 错误:(-210:不支持的格式或格式组合)功能'create'中的硬件视频解码器不支持视频源
- 哪个C++规范开始支持 std::vector
- 如何检测VS C++编译器是否支持C++11?
- CertGetCertificateChain 具有支持的内存存储和证书信任列表
- Casablanca/cpprestsdk listener.support接受函数,但不支持方法
- 将 IPv6 支持添加到雨量计
- 为什么C++不支持对未初始化变量进行智能分析?
- LMDB 是否支持随机读取?
- 在 c++ 中连接字符串和整数,以便在 C++ 11 不支持计算机的情况下读取多个文件
- 便携式检测__VA_OPT__支持?
- 对大文件的便携式支持