Ограничен ли fopen() файловой системой?

Я написал программу для создания больших файлов .SQL для быстрого заполнения очень больших баз данных. Я написал это на PHP. Когда я начал программировать, я использовал fopen() и fwrite(). Когда файлы становились слишком большими, программа возвращала управление оболочке, и файл становился неполным.

К сожалению, я точно не знаю, насколько большим является «слишком большой». Я думаю, что это могло быть около 4 ГБ.

Чтобы решить эту проблему, я отправил файл echo на стандартный вывод. Я перенаправил его, когда вызвал программу так:

[root@localhost]$ php generatesql.php > myfile.sql

Который работал как шарм. Мой выходной файл получился около 10 ГБ.

Тогда у меня возникает вопрос: ограничиваются ли fopen() и fwrite() файловой системой с точки зрения размера файла, который они могут создать? Если так; это ограничение PHP? Это происходит и в других языках?


person KeatsKelleher    schedule 19.11.2010    source источник
comment
Покажите какой-нибудь код... Вероятно, это потому, что вы работаете в 32-битной операционной системе, и вы переполняете ограничение int на позицию в файле (но это просто предположение, если вы не вызвали ftell или fseek)...   -  person ircmaxell    schedule 20.11.2010
comment
Покажу код, как только вернусь из офиса.   -  person KeatsKelleher    schedule 20.11.2010
comment
@ircmaxell: fseek() была вызвана в самом конце выполнения.   -  person KeatsKelleher    schedule 20.11.2010


Ответы (4)


Что, вероятно, происходит, так это то, что базовая сборка PHP является 32-битной и не может обрабатывать указатели файлов> 4 ГБ - см. это связанный вопрос.

Ваша базовая ОС, очевидно, способна хранить большие файлы, поэтому вы можете перенаправить стандартный вывод на большой файл.

Между прочим, файл SQL, скорее всего, будет сильно сжимаемым, поэтому вы можете рассмотреть возможность использования gzip fopen wrapper для сжатия файла при его записи.

$file = 'compress.zlib:///path/to/my/file.sql.gz';
$f = fopen($file, 'wb');

    //just write as normal...
    fwrite($f, 'CREATE TABLE foo (....)');

fclose($f);

Ваш дамп будет в несколько раз меньше первоначального размера, и вы можете восстановить его, просто передав вывод из zcat в клиент SQL, например для MySQL

zcat /path/to/my/file.sql.gz | mysql mydatabase
person Paul Dixon    schedule 19.11.2010
comment
У меня 32-битная версия и я не могу генерировать файлы › 2GiB. stackoverflow.com/q/19438203/89771 - person Alix Axel; 18.10.2013

И да и нет. Это не fopen() или fwrite(), которые ограничены напрямую, это файлы, которые не могут превышать некоторые размеры в зависимости от файловой системы. Взгляните на Сравнение файловых систем в Википедии.

person KingCrunch    schedule 19.11.2010
comment
Но если это так, то как получилось, что перенаправление вывода сработало при создании файла ~ 10 ГБ для OP? - person Chetan; 20.11.2010
comment
Почему нет? f*() (файловые функции) обычно работают с потоками. Поэтому, если вы вызываете fwrite(), он буферизует только до (я предполагаю) 4 КБ, прежде чем записывать вывод непосредственно в открытый поток (возвращаемое значение fopen()) . Теперь ваш скрипт запускается и запускается и заполняет файл, но в какой-то момент файловая система блокирует любые дальнейшие данные из-за максимального размера файла. На самом деле, я не знаю, действительно ли это происходит с вами, потому что 10 ГБ — это нечетное значение. В любом случае: попробуйте разделить его на несколько файлов (скажем, ‹4 ГБ). Вы не знаете точно, на FS файлы сохраняются позже. - person KingCrunch; 20.11.2010

Возможно ли, что ваш скрипт выполняется слишком долго и истекло время ожидания?

В качестве альтернативы, возможно ли, что вы достигаете пределов памяти в сценарии?

person zzzzBov    schedule 19.11.2010
comment
он выполняется с помощью php-cli; определенно не проблема тайм-аута. если бы предел памяти был достигнут, было бы сообщение об ошибке. - person KeatsKelleher; 20.11.2010

Вы можете записать более 2 ГБ данных в поток, а не в файл (поскольку внутренний указатель файла fseek превышает ограничения PHP, а потоки обычно недоступны для поиска )

<? $target = fopen('test.tar', 'w'); //this is a file, limited by php to 2GB $body = str_repeat("===", 1024 * 1024); while(true) fwrite($target, $test);

<? $target = popen('cat > test.tar', 'w'); //this is a stream, no limitation here $body = str_repeat("===", 1024 * 1024); while(true) fwrite($target, $test);

person 131    schedule 01.07.2016