对大文件的便携式支持
Portable support for large files
我看了
- this
- and this
- and this
而且我仍然不知道如何以可移植的方式了解大于 4 GB 的文件大小。
值得注意的是,合并一些答案无法为 Cygwin 编译,而其他答案则无法为 Linux。
事实证明,各种标准定义了相当多的功能:
fseek
/ftell
由ANSI标准库定义。它几乎无处不在。它保证仅使用 32 位整数,但不是必需的(这意味着您可能会立即获得对大文件的支持)。
fseeko
/ftello
这是由 POSIX 标准定义的。在许多平台上,根据 _FILE_OFFSET_BITS
的值,它会导致 off_t
被定义为 off64_t
和 fseeko
被定义为 fseeko64
for _FILE_OFFSET_BITS=64
.
fseeko64
/ftello64
这是 fseeko
和 ftello
的 64 位等价物。我在任何标准中都找不到这方面的信息。
Cygwin 不一致
虽然它符合POSIX,但无论我在Cygwin下定义什么,我都无法编译fseeko
,除非我使用--std=gnu++11
,这显然是无意义的,因为它是一部分POSIX 而不是 GNU 扩展。那么给出了什么?根据 this discussion:
64 bit file access is the natural
file access type for Cygwin. off_t is 8 bytes. There are no foo64
functions for that reason. Just use fopen and friends and you get 64
bit file access for free.
这意味着 #ifdef
对于 POSIX 平台上的 cygwin。
_fseeki64
/ _ftelli64
这些由 Microsoft Visual C++ 定义,并且专门用于其编译器。显然它不支持上面列表中的任何其他内容(fseek
除外),因此您将需要 #ifdef
s.
编辑:实际上我建议不要使用它们和 I'm not the only one who thinks that。我经历了以下字面意思:
wfopen
二进制文件
fwrite
10 个字节
_ftelli64
位置
- 它returns 12 个而不是 10 个字节
看起来这个已经坏掉了。
lseek
和 lseek64
由 POSIX 定义,这些将与使用 open()
从 unistd.h
而不是 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
for 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
}
实际上,您可以检查函数是否使用您的构建系统编译,并相应地定义您自己的常量,例如 HAVE_FTELLO64
,而不是检查对我来说总是脆弱的 #ifdef
s。
请注意,如果您确实决定使用 lseek
/_lseeki64
系列和数字文件描述符而不是 FILE*
结构,您应该注意 [=62] 之间的以下差异=]/fopen
:
open
不使用缓冲,fopen
会。更少的缓冲意味着更差的性能。
open
不能对文本文件进行换行,fopen
可以。
this question 中有更多详细信息。
参考文献:
- 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
我看了
- this
- and this
- and this
而且我仍然不知道如何以可移植的方式了解大于 4 GB 的文件大小。
值得注意的是,合并一些答案无法为 Cygwin 编译,而其他答案则无法为 Linux。
事实证明,各种标准定义了相当多的功能:
fseek
/ftell
由ANSI标准库定义。它几乎无处不在。它保证仅使用 32 位整数,但不是必需的(这意味着您可能会立即获得对大文件的支持)。
fseeko
/ftello
这是由 POSIX 标准定义的。在许多平台上,根据
_FILE_OFFSET_BITS
的值,它会导致off_t
被定义为off64_t
和fseeko
被定义为fseeko64
for_FILE_OFFSET_BITS=64
.fseeko64
/ftello64
这是
fseeko
和ftello
的 64 位等价物。我在任何标准中都找不到这方面的信息。Cygwin 不一致
虽然它符合POSIX,但无论我在Cygwin下定义什么,我都无法编译
fseeko
,除非我使用--std=gnu++11
,这显然是无意义的,因为它是一部分POSIX 而不是 GNU 扩展。那么给出了什么?根据 this discussion:64 bit file access is the natural file access type for Cygwin. off_t is 8 bytes. There are no foo64 functions for that reason. Just use fopen and friends and you get 64 bit file access for free.
这意味着
#ifdef
对于 POSIX 平台上的 cygwin。_fseeki64
/_ftelli64
这些由 Microsoft Visual C++ 定义,并且专门用于其编译器。显然它不支持上面列表中的任何其他内容(
fseek
除外),因此您将需要#ifdef
s.编辑:实际上我建议不要使用它们和 I'm not the only one who thinks that。我经历了以下字面意思:
wfopen
二进制文件fwrite
10 个字节_ftelli64
位置- 它returns 12 个而不是 10 个字节
看起来这个已经坏掉了。
lseek
和lseek64
由 POSIX 定义,这些将与使用
open()
从unistd.h
而不是FILE*
结构打开的整数文件描述符一起使用。这些与 Windows 不兼容。同样,他们使用off_t
数据类型。_lseek
,_lseeki64
这 Windows 相当于
lseek
/lseek64
。奇怪的是,_lseeki64
不使用off_t
而是使用__int64
,所以你 知道 它可以处理大文件。整洁fsetpos
/fgetpos
虽然这些实际上非常便携,但它们几乎无法使用,因为它们对不透明结构而不是整数偏移量进行操作,这意味着您可以添加或减去它们,甚至可以导航到通过其他任何方式获得的文件中的特定位置比通过
fgetpos
.
结论
所以为了让你的程序可移植,根据平台,你应该使用:
fseeko
(POSIX) + 在 POSIX 上定义 fseek
对于 Cygwin 和默认实现_lseeki64
for Windows - 或者,如果你设法绕过它 -_fseeki64
.
_FILE_OFFSET_BITS=64
使用_ftelli64
的示例:
int64_t portable_ftell(FILE *a)
{
#ifdef __CYGWIN__
return ftell(a);
#elif defined (_WIN32)
return _ftelli64(a);
#else
return ftello(a);
#endif
}
实际上,您可以检查函数是否使用您的构建系统编译,并相应地定义您自己的常量,例如 HAVE_FTELLO64
,而不是检查对我来说总是脆弱的 #ifdef
s。
请注意,如果您确实决定使用 lseek
/_lseeki64
系列和数字文件描述符而不是 FILE*
结构,您应该注意 [=62] 之间的以下差异=]/fopen
:
open
不使用缓冲,fopen
会。更少的缓冲意味着更差的性能。open
不能对文本文件进行换行,fopen
可以。this question 中有更多详细信息。
参考文献:
- 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