Наличие файлов, которые занимают больше места для хранения, чем их отображаемая длина, не является обычным явлением, поэтому, если у вас нет веской причины для этого (например, вы хотите использовать длину файла, чтобы отслеживать, как далеко продвинулась загрузка, с целью возобновления это), лучше всего использовать поведение fallocate(2) по умолчанию. (без FALLOC_FL_KEEP_SIZE). Это та же семантика, что и у posix_fallocate(3).
На странице руководства для fallocate(2) даже говорится, что его поведение по умолчанию (без флагов) задумано как оптимальный способ реализации posix_fallocate(3), и указывает на это как на переносимый способ распределения пространства.
Исходный вопрос говорит что-то о записи нулей в файл. Ни один из этих вызовов не записывает ничего, кроме метаданных. Если вы читаете из пространства, которое было предварительно выделено, но еще не записано, вы получите нули (а не то, что было в этом дисковом пространстве ранее, это было бы большой дырой в безопасности). Вы можете читать только до конца файла (длина, установленная с помощью fallocate, ftruncate или другими способами), поэтому, если у вас есть файл нулевой длины и вы можете выполнить Fallocate с FALLOC_FL_KEEP_SIZE, вы ничего не сможете прочитать. Ничего общего с предварительным выделением, просто семантика размера файла.
Поэтому, если вас устраивает семантика 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) = ?
на флешке фат32:
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 а>. Для программы, которая работает с большими файлами (например, торрентами), это может быть очень плохо.
Вы можете поблагодарить семантику POSIX за то, что она потребовала от glibc сделать это, поскольку она не определяет код ошибки для «файловая система не поддерживает предварительное выделение». http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fallocate. HTMLа>. Это также гарантирует, что в случае успешного вызова последующие записи в выделенную область не завершатся ошибкой из-за нехватки места на диске. Таким образом, дизайн posix не обеспечивает способа обработки случая, когда вызывающая сторона заботится об эффективности/производительности/фрагментации, а не о гарантиях дискового пространства. Это вынуждает реализацию POSIX выполнять цикл чтения-записи, а не оставлять это как вариант для вызывающих программ, которым требуется гарантия дискового пространства. Спасибо POSIX...
Я не знаю, возвращаются ли не-GNU реализации posix_fallocate к чрезвычайно медленному поведению при чтении-записи, когда файловая система не поддерживает предварительное выделение. (FreeBSD, Solaris?). По-видимому, OS X (Darwin) не реализует posix_fallocate, если только он не совсем новый.
Если вы хотите поддерживать предварительное выделение на множестве платформ, но без возврата к чтению и записи, если в ОС есть способ просто попытаться выполнить предварительное выделение, вы должны использовать любой доступный метод для конкретной платформы. например проверьте 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. Кроме того, нашел этот список сообщений 2007 года для OS X Darwin: http://lists.apple.com/archives/darwin-dev/2007/Dec/msg00040.html
person
Community
schedule
07.05.2014
fallocate
не меняет размер файла? Это для меня. В противном случае единственная разница между ними заключается в том, чтоfallocate
будет более эффективно работать с ядрами Linux, чемposix_fallocate
, хотя и не переносимым. - person netcoder   schedule 28.12.2012FALLOC_FL_KEEP_SIZE
. Отсутствие установки флага должно дать вам тот же результат для любого из них. - person netcoder   schedule 28.12.2012