+-
C-Fallocate vs posix_fallocate
我正在争论在posix_fallocate和fallocate之间使用哪个函数.
posix_fallocate立即写入一个文件(将字符初始化为NULL).但是,fallocate不会更改文件大小(使用FALLOC_FL_KEEP_SIZE标志时).根据我的实验,fallocate似乎不会向文件写入NULL或零个字符.

有人可以根据您的经验发表评论吗?谢谢你的时间.

最佳答案
文件占用的存储空间多于其显示的长度是不常见的,因此,除非您有充分的理由这样做(例如,出于恢复目的,您希望使用文件长度来跟踪下载量) ),最好使用默认的fallocate(2)行为. (没有FALLOC_FL_KEEP_SIZE).这与posix_fallocate(3)的语义相同.

fallocate(2)的手册页甚至说,它的默认行为(无标志)旨在作为实现posix_fallocate(3)的最佳方式,并指出这是分配空间的可移植方式.

最初的问题是关于将零写入文件的.除元数据外,这些调用均未写入任何内容.如果您从已预分配但尚未写入的空间中读取数据,则会得到零(而不是该磁盘空间中的任何内容,那将是一个很大的安全漏洞).您只能读取文件的末尾(长度,由fallocate,ftruncate或其他各种方式设置),因此,如果您有一个零长度的文件,并且使用FALLOC_FL_KEEP_SIZE进行fallocate,那么您将无法读取任何内容.与预分配无关,仅与文件大小语义有关.

因此,如果您对POSIX语义比较满意,请使用它,因为它更具可移植性.每个GNU / Linux系统都将支持posix_fallocate(3),但其他一些系统也将支持.

但是,由于POSIX语义的原因,它并不是那么简单.如果在不支持预分配的文件系统上使用它,它仍然会成功,但是可以通过回退到在文件的每个块中实际写入零来实现.

测试程序:

#include <fcntl.h>
int main() {
    int fd = open("foo", O_RDWR|O_CREAT, 0666);
    if (fd < 0) return 1;
    return posix_fallocate(fd, 0, 400000);
}

在XFS上

$strace ~/src/c/falloc
...
open("foo", O_RDWR|O_CREAT, 0666) = 3
fallocate(3, 0, 0, 400000)              = 0
exit_group(0)                           = ?

在fat32闪存驱动器上:

open("foo", O_RDWR|O_CREAT, 0666) = 3
fallocate(3, 0, 0, 400000)              = -1 EOPNOTSUPP (Operation not supported)
fstat(3, {st_mode=S_IFREG|0755, st_size=400000, ...}) = 0
fstatfs(3, {f_type="MSDOS_SUPER_MAGIC", f_bsize=65536, f_blocks=122113, f_bfree=38274, f_bavail=38274, f_files=0, f_ffree=0, f_fsid={2145, 0}, f_namelen=1530, f_frsize=65536}) = 0
pread(3, "\0", 1, 6783)                 = 1
pwrite(3, "\0", 1, 6783)                = 1
pread(3, "\0", 1, 72319)                = 1
pwrite(3, "\0", 1, 72319)               = 1
pread(3, "\0", 1, 137855)               = 1
pwrite(3, "\0", 1, 137855)              = 1
pread(3, "\0", 1, 203391)               = 1
pwrite(3, "\0", 1, 203391)              = 1
pread(3, "\0", 1, 268927)               = 1
pwrite(3, "\0", 1, 268927)              = 1
pread(3, "\0", 1, 334463)               = 1
pwrite(3, "\0", 1, 334463)              = 1
pread(3, "\0", 1, 399999)               = 1
pwrite(3, "\0", 1, 399999)              = 1
exit_group(0)                           = ?

如果文件还没有那么长,它的确避免了读取操作,但是写每个块仍然很糟糕.

如果您想要简单的东西,我仍然会选择posix_fallocate.有一个FreeBSD手册页,它由POSIX指定,因此每个POSIX兼容的系统都提供它.一个缺点是在不支持预分配的文件系统上使用glibc会使它感到可怕.参见例如https://plus.google.com/+AaronSeigo/posts/FGtXM13QuhQ.对于使用大文件(例如torrents)的程序,这可能真的很糟糕.

您可以感谢POSIX语义要求glibc这样做,因为它没有为“文件系统不支持预分配”定义错误代码. http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fallocate.html.它还保证,如果调用成功,则由于磁盘空间不足,随后对分配的区域的写操作不会失败.因此,posix设计没有提供一种方法来处理调用者关心效率/性能/碎片而不是磁盘空间保证的情况.这将强制POSIX实现执行读写循环,而不是将其作为需要磁盘空间保证的调用者的选项.谢谢POSIX …

我不知道当文件系统不支持预分配时,posix_fallocate的非GNU实现是否同样会退回到极慢的读写行为. (FreeBSD,Solaris?).显然,OS X(Darwin)不会实现posix_fallocate,除非它是最近的.

如果您希望在许多平台上支持预分配,但是如果OS可以尝试进行预分配,而又不至于先后读写,则必须使用任何可用的特定于平台的方法.例如查看
https://github.com/arvidn/libtorrent/blob/master/src/file.cpp

搜索文件:: set_size.它有几个ifdeffed块,具体取决于编译目标所支持的块,从Windows代码开始加载DLL并在其中进行填充,然后依次是fcntl F_PREALLOCATE或fcntl F_ALLOCSP64,然后是Linux fallocate(2),然后回退到使用posix_fallocate.另外,在OS X Darwin的2007年列表列表中找到了http://lists.apple.com/archives/darwin-dev/2007/Dec/msg00040.html

点击查看更多相关文章

转载注明原文:C-Fallocate vs posix_fallocate - 乐贴网