表示された長さよりも多くのストレージ スペースを占有するファイルを持つことは一般的ではないため、そうする正当な理由がない限り (たとえば、ファイルの長さを使用して、ダウンロードがどこまで到達したかを追跡し、再開する目的で使用する場合)デフォルトの 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 の man ページがあり、POSIX で指定されているため、すべての POSIX 準拠システムで提供されています。1 つの欠点は、事前割り当てをサポートしていないファイルシステムで glibc を使用すると恐ろしいことです。たとえば、https://plus.google.com/+AaronSeigo/posts/FGtXM13QuhQを参照してください。大きなファイル (トレントなど) を扱うプログラムの場合、これは非常に悪いことです。
「ファイルシステムは事前割り当てをサポートしていません」というエラーコードを定義していないため、これを行うために glibc を必要とする POSIX セマンティクスに感謝できます。 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を確認してください。
file::set_size を検索します。コンパイル ターゲットがサポートするものに応じて、いくつかの ifdefed ブロックがあり、DLL をロードしてそこで何かを実行する Windows コードから始まり、次に 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