Php прочитать файл построчно
Одним из преимуществ работы с современными языками программирования, такими как PHP, является количество доступных возможностей. PHP легко мог бы присвоить девиз языка Perl, «Существует несколько способов сделать что-либо», особенно, когда речь идет об обработке файлов. Но при изобилии доступных средств, возникает вопрос, какое из них лучше для выполнения работы. Конечно, в действительности, ответ на этот вопрос зависит от того, какие цели вы ставите при обработке файла, поэтому изучение всех возможностей языка стоит потраченного времени.
Создаём PHP парсер файла — начальные условия
Перед тем, как мы начнём, пару слов о задаче, для которой я создавал парсер файла на PHP, а затем выбирал из реализованных вариантов оптимальный.
Однажды у меня на работе возникла проблема, которая заключалась в том, что в БД хранились телефоны пользователей в неверном формате. Сам баг я, естественно, без проблем пофиксил.
Но, что делать с неверной информацией, которая на тот момент уже хранились в базе данных? Естественно, её нужно было заменить на корректную.
Для этого мне был предоставлен текстовый файл с идентификаторами пользователей и их телефонами, которые нужно было перенести в БД.
Должен сказать, он получился весьма увесистым: 352 Кбайта и 8223 строки текста, в каждой из которых содержался идентификатор пользователя и его телефон в формате id_пользователя:номер_телефона.
Словом, вся задача заключалась в построчном чтении файла PHP средствами, выделения из строки идентификатора и телефона с последующим обновлением значения телефона у пользователя в БД, найденного по айдишнику.
Мой проект был реализован на PHP фреймворке Yii, следовательно в дальнейших примерах кода вы встретите элементы его API для работы с БД, в частности, поэтому не пугайтесь 🙂
После анализа имеющихся в языке конструкций, а также опыта других разработчиков, по крупицам собранного в Интернете, мне удалось выделить 4 способа, которые я далее вам и продемонстрирую.
Ну, а после я расскажу, по каким критериям и как именно я выбирал среди них оптимальный вариант. И, естественно, поделюсь результатами 🙂
Так что данная статья — отличная тренировка терпеливости 🙂 Суть её будет заключаться в подробном изучении следующего материала вплоть до результатов, которые будут ждать вас в конце. По ходу, кстати, можете поработать ещё и над фантазией, предполагая, как именно будет выбираться идеальный вариант.
Примечания
Замечание: Если у вас возникают проблемы с распознаванием PHP концов строк при чтении или создании файлов на Macintosh-совместимом компьютере, включение опции auto_detect_line_endings может помочь решить проблему.
Замечание:
Программисты, привыкшие к семантике 'C' функции fgets() , должны принимать во внимание разницу в том, каким образом возвращается признак достижения конца файла (EOF).
Данная функция похожа на функцию fgets() , с той разницей, что она производит анализ строки на наличие записей в формате CSV и возвращает найденные поля в качестве массива.
Функция fgetss
Функция fgetss отличается от традиционных функций для работы с файлами и дает вам лучшее представление о возможностях PHP. Она работает наподобие fgets , но отбрасывает любые обнаруженные ею теги HTML или PHP, оставляя только «голый» текст. Возьмем приведенный ниже HTML-файл.
Листинг 2. Пример файла HTML
Пропустим его через функцию fgetss .
Листинг 3. Использование fgetss
Вот что вы получите в качестве выходных данных:
Примеры
$fp = fopen ( 'somefile.txt' , 'r' );
if (! $fp ) echo 'Ошибка при открытии файла somefile.txt' ;
>
while ( false !== ( $char = fgetc ( $fp ))) echo " $char \n" ;
>
?>?php
PHP парсинг файла в массив с помощью file()
Данный метод чтения файла в PHP предполагает использование функции file(), которая открывает файл и помещает его содержимое в массив. При этом элементами массива будут являться, как раз, строки считываемого файла, что в моей ситуации отлично подходит.
Код данного варианта PHP парсера файла получился следующий:
Как видите, от предыдущего способа чтения файла в PHP данный отличается только своим началом, где файл открывается и сразу же считывается функцией file() вместо связки fopen() + fgets(), как ранее.
Далее код такой же.
Функция fgets
Возвращаясь на несколько строк назад в Листинге 1, вы попадаете в самый центр процесса обработки файлов: непосредственно чтение файла. Функция fgets — это выбранное вами «оружие» для первого примера. Она захватывает строчку данных из файла и возвращает ее как строку. Оттуда вы можете выводить данные или обрабатывать их иным образом. В примере, приведенном в Листинге 1, распечатывается весь файл целиком.
Если вы решите ограничить размер порции данных, с которой работаете, можно добавить fgets аргумент для ограничения максимальной длины строки захватываемых данных. Например, используйте следующий программный код для ограничения длины строки в 80 символов:
Вспомните «\0», указатель конца строки в C и установите длину на один символ больше, чем вам в действительности необходимо. Как видите, в приведенном выше примере используется 81, тогда как вам нужно 80 символов. Сделайте вашей привычкой добавление дополнительного символа всегда, когда вам понадобится задать ограничение длины строки для данной функции.
Хороший стиль программирования
Никогда не считайте, что все в вашей программе будет работать так, как было задумано. Например: что, если файл, который вы ищете, был перемещен? Что, если в результате изменения прав доступа вы не можете прочитать содержимое файла? Можно заранее проверить наличие файла и права на его чтение, воспользовавшись методами file_exists и is_readable .
Листинг 7. Использование file_exists и is_readable
Тем не менее, на практике этот фрагмент программы будет, пожалуй, чрезмерным для вашей задачи. Обработка значений, возвращаемых fopen , проще и точнее.
Как и fopen , функции file_get_contents , file и readfile возвращают значение False, если не удается открыть или обработать файл. Функции fgets , fgetss , fread , fscanf и fclose также возвращают значение False при возникновении ошибки. Конечно, за исключением fclose , вы, вероятно уже обработали возвращенные ими результаты. Что касается fclose , мало что можно сделать, если дескриптор файла не закрывается должным образом, поэтому проверка возвращенного значения функции fclose , как правило, является излишней.
Примечания
Замечание:
Эта функция принимает во внимание настройки локали. К примеру, если LANG установлена в en_US.UTF-8, то файлы в однобайтовой кодировке будут неправильно прочитаны этой функцией.
Приветствую вас, друзья! 🙂
Думаю, что, если не все, то, уж точно большинство из вас сталкивались на практике с необходимостью чтения информации из txt файлов на уровне серверных скриптов. У меня, по крайней мере, таких случаев было несколько, о последнем из которых я вам сегодня и расскажу.
Ничего в этом сложного нет, но иногда глаза разбегаются от обилия вариантов, предоставляемых средствами серверных языков. Если говорить конкретно о PHP, на котором я сейчас программирую, то с помощью его функций можно считывать содержимое файлов и построчно, и целиком в строку, и в массив, причём для последнего варианта существует ещё несколько способов… Вот такие пироги 🙂
К сожалению только, данные методы работают с различной скоростью для файлов разной структуры, и о скорости их работы нет ни единого слова в официальной документации; об этом можно судить лишь на практике, перебирая все возможные варианты.
Поэтому, сегодня я продемонстрирую вам работу различных функций PHP для чтения файлов, чтобы, когда вам нужно будет создать PHP парсер файла для решения реальных задач, вы знали, из чего выбирать. А также подскажу, как именно в «боевых условиях» сделать правильный выбор.
Возвращаемые значения
Возвращает строку размером в length - 1 байт, прочитанную из дескриптора файла, на который указывает параметр handle . Если данных для чтения больше нет, то возвращает FALSE .
В случае возникновения ошибки возвращает FALSE .
PHP чтение файла в переменную с помощью fread()
Ещё одной функцией PHP для разбора файла является fread(), с помощью которой можно читать различные фрагменты файла указанной длины. Чтобы прочитать файл в PHP целиком, в качестве размера фрагмента я указал размер файла, полученный с помощью функции filesize():
Данный способ чтения файла PHP средствами, на самом деле, очень похож на предыдущий, т.к., несмотря на то, что с помощью PHP данные из файла изначально считываются не в массив, а в строковую переменную, далее она всё равно преобразуется в массив, т.к. с ним проще работать, чем со строкой.
Преобразование строки в массив на PHP проще всего сделать с помощью уже применявшейся сегодня функции explode(), в качестве разделителя в которую был передан символ начала строки.
А дальше всё идёт по накатанной 🙂
Список параметров
Корректный файловый указатель на файл, успешно открытый при помощи fopen() , popen() или fsockopen() .
Должен быть больше самой длинной строки (в символах), найденной в CSV-файле (включая завершающий символ конца строки). Данный параметр стал необязательным в PHP 5. Если этот аргумент не указан (или равен 0 в версиях PHP 5.1.0 и выше), максимальная длина строки не ограничена, но функция работает немного медленнее.
Необязательный параметр delimiter устанавливает разделитель поля (только один символ).
Необязательный параметр enclosure устанавливает символ ограничителя поля (только один символ).
Необязательный параметр escape устанавливает экранирующий символ (только один символ).
User Contributed Notes 5 notes
The best and simplest way to get input from a user in the CLI with only PHP is to use fgetc() function with the STDIN constant:
echo 'Are you sure you want to quit? (y/n) ' ;
$input = fgetc ( STDIN );
I was using command-line PHP to create an interactive script and wanted the user to enter just one character of input - in response a Yes/No question. Had some trouble finding a way to do so using fgets(), fgetc(), various suggestions using readline(), popen(), etc. Came up with the following that works quite nicely:
$ans = strtolower( trim( `bash -c "read -n 1 -t 10 ANS ; echo \\\$ANS"` ) );
To read a single key-press in CLI mode, you can either use ncurses (which will probably require additional modules for PHP) or get nasty with the *nix "/bin/stty" command)
function stty ( $options ) exec ( $cmd = "/bin/stty $options " , $output , $el );
$el AND die( "exec( $cmd ) failed" );
return implode ( " " , $output );
>
function getchar ( $echo = false ) $echo = $echo ? "" : "-echo" ;
If you call fgetc(HANDLE) multiple times you must clear buffer before, thus get all unwanted chars to the new new line character.
//clear buffer - read all unwanted characters
while(fgetc(STDIN) != "\n");
//get first character from STDIN
$first = fgetc(STDIN);
>
You can't just simple print separated characters of a text which is encoded in multibyte character set like this;
Because fgetc() will break each multibyte character on its every byte. Consider this example:
$path = 'foo/cyrillic.txt' ;
$handle = fopen ( $path , 'rb' );
while ( FALSE !== ( $ch = fgetc ( $handle ))) $curs = ftell ( $hanlde );
print "[ $curs :] $ch \n" ;
>
/* The result will be something like this:
[1]: [2]: h
[3]: 2
[4]: >
[5]: �
[6]: �
[7]: �
[8]: �
[9]: �
[10]: �
[11]:
[12]: �
[13]: �
[14]: �
[15]: �
[16]: �
*/ ?>
I don't think this is the best, but it can be a workaround:
$path = 'path/to/your/file.ext' ;
if (! $handle = fopen ( $path , 'rb' )) echo "Can't open ( $path ) file';
exit;
>
$mbch = ''; // keeps the first byte of 2-byte cyrillic letters
while (FALSE !== ( $ch = fgetc( $handle ))) <
//check for the sign of 2-byte cyrillic letters
if (empty( $mbch ) && (FALSE !== array_search(ord( $ch ), Array(208,209,129)))) $mbch = $ch ; // keep the first byte
continue;
>
$curs = ftell( $handle );
print " [ $curs ]: " . $mbch . $ch . PHP_EOL;
// or print " [ $curs ]: $mbch$ch \ n ";
if (!empty( $mbch )) $mbch = ''; // erase the byte after using
>
?>
Указатель на файл должен быть корректным и указывать на файл, успешно открытый функциями fopen() или fsockopen() (и все еще не закрытым функцией fclose() ).
Чтение заканчивается по достижении length - 1 байт, если встретилась новая строка (которая включается в возвращаемый результат) или конец файла (что встретилось первым). Если длина не указана, чтение из потока будет продолжаться до тех пор, пока не достигнет конца строки.
Замечание:
До версии PHP 4.3.0, опущение этого параметра означало, что длина строки будет равна 1024 символам. Если большинство строк в файле больше 8 килобайт, в целях производительности вашего скрипта стоит указать максимальную длину строки.
Разбор файла в PHP — выводы
Как я уже и говорил в начале, мои опыты не являются безупречными и опираться исключительно на полученные в их ходе результаты не стоит, т.к., несмотря на быстродействие file_get_contents() в моей ситуации, бывают случаи, когда намного удобнее и эффективнее использовать другие приведённые мною PHP парсеры файлов.
Кроме того, не стоит забывать, что PHP сам по себе является синхронным языком программирования, т.е. все серверные операции происходят последовательно без возможности настройки их параллельного выполнения, в том числе, и на разных ядрах серверного процессора.
Следовательно, на время выполнения операций, прописанных в PHP коде, может влиять целый ряд факторов, среди которых основным является нагруженность ядра в момент работы PHP приложения.
Я это особенно ощутил во время проведения опытов, когда один и тот же PHP парсер файла отработал за 9, затем за 12, а потом снова за 9 секунд на трёх последовательных итерациях из-за банального запуска проводника Windows во время второго случая, который, естественно, тоже требует серверных ресурсов.
Учитывая данные особенности, я проводил эксперименты практически одновременно, друг за другом, при одинаковом комплекте запущенных программ, чтобы не распылять ресурсы серверного железа.
Поэтому в дальнейшем, при проведении подобных экспериментов с PHP конструкциями действуйте аналогичным образом, т.к. это, по сути, единственный способ привести эксперименты к равным условиям.
Ну, а если найти полностью незадействованное ядро не получится (что при уровне современного ПО не удивительно), то вы хотя бы сможете найти самое слабонагруженное или, хотя бы, со статической нагрузкой, которая не меняется во времени.
Надеюсь, что мои наблюдения и рекомендации будут вам полезны, равно как и мои сегодняшние эксперименты с PHP парсерами файлов.
Подытоживая, хочу сказать, что приведённые в статье фрагменты кода могут использоваться не только для парсинга текстовых файлов в PHP, но и отлично подойдут для других форматов, например, для разбора CSV файлов дампа базы данных MySQL.
Пишите ваши отзывы, как положительные, так и отрицательные в комментариях под статьёй — мне необходимо любое ваше мнение для дальнейшего развития 🙂
Также буду благодарен, если поделитесь данной статьёй со своими друзьями в социальных сетях с помощью кнопочек ниже.
До новых встреч! 🙂
Функция fread
Функция fgets — лишь одна из многих имеющихся функций для чтения файла. Это одна из наиболее часто использующихся функций, поскольку построчная обработка файла в большинстве случаев оказывается самой разумной. На самом деле, сходные возможности предлагают несколько других функций. Как бы то ни было, построчный анализ — это не всегда то, что вам нужно.
И здесь мы обращаемся к fread . Функция fread используется в несколько иных целях, чем fgets : она предназначена для чтения из двоичных файлов (то есть файлов, не состоящих изначально из текста, удобочитаемого для человека). Поскольку понятие «строк» не актуально для двоичных файлов (логические структуры данных обычно не разбиваются на строки), вы должны указывать количество байтов, которое нужно считывать.
В приведенном выше примере считывается 4096 байтов (4 KB) данных. Обратите внимание, что, независимо от указанного вами значения, fread будет считывать не более 8192 байтов (8 KB).
Допуская, что файл не более 8 KB, фрагмент программы, приведенный ниже, должен считывать весь файл в одну строку.
Если размер файла больше, вам придется использовать цикл для считывания оставшейся его части.
Примеры
$handle = @ fopen ( "/tmp/inputfile.txt" , "r" );
if ( $handle ) while (( $buffer = fgets ( $handle , 4096 )) !== false ) echo $buffer ;
>
if (! feof ( $handle )) echo "Error: unexpected fgets() fail\n" ;
>
fclose ( $handle );
>
?>?php
Возвращаемые значения
Возвращает строку с одним символом, прочтённым из файла, на который указывает stream . Возвращает false при достижении EOF.
Эта функция может возвращать как логическое значение false , так и значение не типа boolean, которое приводится к false . За более подробной информацией обратитесь к разделу Булев тип. Используйте оператор === для проверки значения, возвращаемого этой функцией.
Примеры
$row = 1 ;if (( $handle = fopen ( "test.csv" , "r" )) !== FALSE ) while (( $data = fgetcsv ( $handle , 1000 , "," )) !== FALSE ) $num = count ( $data );
echo "
$num полей в строке $row :
$row ++;
for ( $c = 0 ; $c < $num ; $c ++) echo $data [ $c ] . "
\n" ;
>
>
fclose ( $handle );
>
?>?php
Чтение файла в PHP построчно с помощью fgets()
Для того, чтобы прочитать файл построчно, в PHP есть специальная функция fgets(). Чтобы с её помощью считать содержимое всего файла, её нужно вызывать в цикле, проходясь по всем строкам.
В итоге, PHP парсер файла, реализующий данный алгоритм, у меня принял следующий вид:
Немного расшифрую свою писанину, если у кого-то возникнут сложности в понимании.
В самом начале, переменной $filename присваивается значение имени файла, который будет парситься, с полным путём к нему. Далее следуют PHP проверка существования файла и читаем ли он с помощью функций file_exists() и is_readable() соответственно.
Если файл открыть получилось, то мы проходимся по всем его строкам в цикле, пока файл не закончится, и, если строка не пустая, разделяем её по символу двоеточия функцией explode().
Затем проверяем, что id пользователя и его телефон не пустые, ищем пользователя в БД по айдишнику и, если таковой существует, то обновляем ему номер телефона, убрав из значения номера предварительно символы переноса и начала новой строки.
Ну, и ещё я использовал PHP функции strtolower() и strtoupper() для проверки существования в БД пользователя с идентификаторами, которые могли быть прописаны в различных регистрах, т.к. они в моём случае состояли из символов и цифр.
Смотрите также
- fread() - Бинарно-безопасное чтение файла
- fopen() - Открывает файл или URL
- popen() - Открывает файловый указатель процесса
- fsockopen() - Открывает соединение с интернет-сокетом или доменным сокетом Unix
- fgets() - Читает строку из файла
Функция fscanf
Возвращаясь к обработке строк, отметим, что fscanf также является преемницей традиционной файловой библиотечной функции C. Если вы не знакомы с ней, fscanf считывает поля данных в переменные из файла.
Создаём PHP парсер файла на базе file_get_contents()
Ну, и напоследок, я решил реализовать PHP парсинг файла с помощью функции file_get_contents(), которая, как раз и предназначена для чтения файла целиком в строку, т.е. работает, практически, как fread($fp, filesize($filename)).
За тем лишь исключением, что file_get_contents() самостоятельно открывает файл и считывает его, в то время как для использования fread() нужно было предварительно открыть файл через fopen() и получить его указатель для дальнейшего использования.
В целом, код PHP парсера файла на базе file_get_contents() будет практически как и в предыдущем случае:
На этом всё. Пришло время подвести итоги производительности всех перечисленных вариантов и выяснить, какой же PHP парсер файла оказался самым оптимальным для дальнейшего использования.
Функция fopen
Функция fopen устанавливает связь с файлом. Я говорю «устанавливает связь, » поскольку, кроме открытия файла, fopen может открыть и URL:
Это строка программы создает связь с вышеуказанной страницей и позволяет вам начать ее чтение как локального файла.
Примечание: Параметр "r" , использованный в fopen , указывает на то, что файл открыт только для чтения. Поскольку запись в файл не входит в круг вопросов, рассматриваемых в данной статье, я не стану перечислять все возможные значения параметра. Тем не менее, вам необходимо изменить "r" на "rb" если вы производите чтение из двоичных файлов для межплатформенной совместимости. Ниже будет приведен пример данного типа.
Список изменений
Версия | Описание |
---|---|
5.3.0 | Добавлен параметр escape |
5.1.0 | Параметр length стал необязательным. По умолчанию равен 0, что означает отсутствие ограничения длины. |
4.3.5 | fgetcsv() теперь безопасна для обработки бинарных данных |
Какой способ обработки файлов в PHP является оптимальным?
Чтобы выбрать из найденных вариантов самый оптимальный, т.е. самый быстрый, я решил определить время выполнения скрипта PHP в каждом случае. Для этого я воспользовался методикой, описанной в статье по ссылке.
Сами по себе PHP функции чтения файлов достаточно шустрые, поэтому, чтобы добиться хоть каких-то более-менее осязаемых цифр времени их работы, я специально оставил в тестируемых фрагментах операции с базой данных, которые во всех случаях были одни и те же.
Время работы PHP скрипта я также решил для удобства округлять до третьего знака после запятой, т.е. до тысячных долей секунд (хотя, можно было ограничиться и сотыми, на самом деле).
Помню, когда я учился в школе и писал свою научную работу по физике (да, был такой опыт 🙂 ) на её защите перед университетскими преподавателями меня постоянно упрекали за недостаточное количество экспериментов (я делал по 3 опыта для каждого случая). «Светилы науки» называли цифры в 100, ну или, хотя бы, в 10 экспериментов для сравнения различных ситуаций, чтобы можно было делать какое-то их сопоставление и минимизировать вероятность случайного превосходства одного над другим.
Да, досталось мне тогда от них крепко, но их рекомендации я хорошо усвоил, что даже сейчас об этом помню, хотя прошло уже более 10 лет с тех пор. Тем более, что данные рекомендации действительно были основаны на законах математической статистики и теории вероятности.
Ну, на научность своих нынешних экспериментов я в данной статье не претендую, поэтому число в 100 экспериментов я посчитал излишне большим, а процесс их проведения — слишком утомительным занятием.
В итоге, я решил ограничиться 10 экспериментами для каждого варианта PHP парсера файла, чего, как оказалось в итоге, оказалось вполне достаточно, чтобы выделить явного лидера без всякой подтасовки фактов и зацепок за сотые и тысячные доли секунды превосходства.
Результаты вычислений времени работы разработанных мною PHP парсеров файла представлены в следующей таблице и рассортированы по PHP функциям, на базе которых они работают.
Эксперимент | fgets() | file() | fread() | file_get_contents() |
1 | 9,147 | 9,722 | 10,539 | 2,008 |
2 | 8,950 | 9,006 | 9,495 | 1,733 |
3 | 8,821 | 8,845 | 9,207 | 1,642 |
4 | 8,717 | 8,876 | 8,931 | 1,758 |
5 | 9,010 | 9,091 | 8,703 | 1,635 |
6 | 9,110 | 8,640 | 9,712 | 1,633 |
7 | 9,074 | 9,626 | 9,13 | 1,645 |
8 | 8,886 | 9,204 | 9,048 | 1,701 |
9 | 8,667 | 8,918 | 9,438 | 1,713 |
10 | 8,852 | 9,197 | 9,537 | 1,567 |
Среднее | 8,923 | 9,113 | 9,374 | 1,704 |
Как видите, помимо значений времени выполнения скрипта в каждом из 10 экспериментов, я решил подсчитать среднюю температуру по больнице 🙂
А именно, арифметическое среднее время работы каждого PHP парсера файла, чтобы можно было выявить лидера.
И им оказался, как видите, последний вариант, реализованный на базе функции file_get_contents(), который выполняет чтение содержимого файла в строковую переменную с дальнейшим его преобразованием в массив и обработкой в цикле.
Все остальные варианты PHP парсеров файлов работают примерно с одинаковой скоростью.
Почему именно он обогнал своих конкурентов я, если честно, не имею ни малейшего понятия. Могу лишь предположить, что операция чтения файла в строку с помощью file_get_contents() требует меньше ресурсов, чем формирование готового массива строк с помощью file().
А превосходство над fgets() и fread() можно списать на то, что перед их использованием требуется открытие файла с помощью fopen(), на что требуется время.
Да, на самом деле, это и не важно, т.к. цифры говорят сами за себя: благодаря использованию функции file_get_contents() PHP парсер файла на его базе работает в 5 раз быстрее остальных, что и повлияло на моё решение использовать его на практике.
Примечания
Замечание: Эта функция безопасна для обработки данных в двоичной форме.
Функция feof
Команда feof определяет, произведено ли чтение до конца файла, и возвращает значение True (Истина) или False (Ложь). Цикл, приведенный в Листинге 1 продолжается, пока не будет достигнут конец файла «myfile.» Обратите внимание, что feof также возвращает False, если вы читаете URL и произошло превышение времени ожидания подключения, поскольку не имеется более данных для считывания.
Нелинейная обработка файла: перемещение по файлу
Конечно, описанные выше функции позволяют вам выполнять чтение из файла лишь последовательно. Более сложные файлы могут потребовать перемещения к разным частям файла в его начале или конце. Для этого вам потребуется функция fseek .
В приведенном выше примере осуществляется переход назад, к началу файла. Если вы не хотите перемещаться в самое начало файла — скажем, одного килобайта вполне достаточно — вы просто пишете:
Начиная с PHP V4.0, доступны также несколько других опций. Например, если нужно перейти вперед на 100 байт от вашей текущей позиции, вы можете использовать следующий код:
Аналогично, переход назад на 100 байт осуществляется посредством:
Если вы хотите перейти назад в положение 100 байт до конца файла, используйте вместо этого SEEK_END .
После достижения нового положения вы можете воспользоваться fgets , fscanf или другой функцией для чтения данных.
Примечание: вы не можете использовать fseek в дескрипторах файла, ссылающихся на URL.
Захват целого файла
Теперь мы переходим к рассмотрению некоторых уникальных возможностей PHP для обработки файлов: обработка больших блоков данных в одной или двух строках. Например, как можно захватить файл и вывести все его содержимое на вашу Web-страницу? Что же, вы видели пример использования цикла с fgets . Но как сделать это проще? Процесс почти смехотворно прост при использовании fgetcontents , которая помещает весь файл в строку.
Хотя это и не лучший вариант, вы можете записать эту команду еще короче:
Данная статья в первую очередь посвящена обработке локальных файлов, однако, стоит отметить, что вы можете также захватить, отобразить и проанализировать другие Web-страницы с помощью описанных функций.
Это команда фактически та же, что и:
Должно быть, вы смотрите на эти примеры и думаете, «Это все-таки слишком трудоемкий способ». PHP-разработчики согласны с вами. Поэтому вы можете сократить приведенную выше команду до:
Конечно, если вам необходимо обрабатывать содержимое файлов, то одна строка, возвращаемая file_get_contents — это, пожалуй, слишком. Вы, возможно, захотите сначала разбить ее на части с помощью функции split() .
Но к чему вам все эти сложности, если есть идеально подходящая функция, которая сделает за вас эту работу? Функция PHP file() выполняет эту задачу в один шаг: она возвращает строковый массив, элементами которого являются строки файла.
Следует заметить, что между двумя приведенными выше примерами есть небольшое отличие. Команда split удаляет знаки перехода на новую строку, тогда как при использовании команды file строки массива оканчиваются знаками перехода на новую строку (также, как и при использовании fgets ).
Возможности PHP, тем не менее, далеко превосходят описанные выше. Вы можете разбить целые .ini-файлы в стиле PHP всего одной командой parse_ini_file . Команда parse_ini_file применима к файлам, сходным с приведенным в Листинге 4.
Листинг 4. Пример файла .ini
Следующие команды представляют файл в виде массива, а затем выводят этот массив на печать:
В результате будут получены следующие выходные данные:
Листинг 5. Выходные данные
Конечно, вы можете заметить, что данная команда объединила разделы. Это действие по умолчанию, но вы легко можете произвести необходимую настройку, воспользовавшись вторым аргументом parse_ini_file : process_sections , который является переменной логического типа (Boolean). Установите значение process_sections как True (истина).
И ваши выходные данные будут иметь вид:
Листинг 6. Выходные данные
PHP помещает данные в легко разбиваемый для анализа многомерный массив.
Но это лишь верхушка айсберга, если говорить об обработке файлов в PHP. Более сложные функции, например tidy_parse_file и xml_parse могут помочь вам с обработкой соответственно HTML- и XML-документов. Обратитесь к разделу Ресурсы, чтобы получить более подробную информацию о работе этих функций. Обе они стоят внимания, если вы будете работать с файлами указанных типов, но вместо рассмотрения всех возможных типов файлов, вы можете внимательно ознакомиться с содержанием данной статьи, где есть несколько неплохих общих правил по работе с функциями, описанными мной к настоящему моменту.
Функция fclose
Пропустим середину Листинга 1 и перейдем в конец; fclose выполняет задачу, противоположную fopen : она закрывает подключение к файлу или URL. После выполнения данной функции вы больше не сможете выполнять чтение из файла или сокета.
Возвращаемые значения
Возвращает индексированный массив с прочтенными полями.
Замечание:
Пустая строка CSV-файла будет возвращена в качестве массива, содержащего единственный элемент null , ошибки в данном случае не возникнет.
Замечание: Если у вас возникают проблемы с распознаванием PHP концов строк при чтении или создании файлов на Macintosh-совместимом компьютере, включение опции auto_detect_line_endings может помочь решить проблему.
fgetcsv() возвращает NULL , если передаётся неверный параметр handle или FALSE при других ошибках, в том числе и по достижению конца файла.
Традиционные методы fopen
Методы fopen , возможно, лучше других знакомы программистам C и C++ былых времен, поскольку в большей или меньшей степени являются именно теми инструментами, которые на протяжении долгих лет были всегда у вас под рукой, если вы работали с этими языками программирования. Для любого из этих методов вы выполняете стандартную процедуру, используя fopen для открытия файла, функцию для чтения данных, а затем fclose для закрытия файла, как показано в Листинге 1.
Листинг 1. Открытие и чтение файла с помощью fgets
Хотя эти функции знакомы большинству опытных программистов, позвольте мне проанализировать их работу. В действительности вы выполняете следующие шаги:
- Открываете файл. $file_handle хранит ссылку на сам файл.
- Проверяете, не достигли ли вы конца файла.
- Продолжаете считывание файла, пока не достигнете конца, печатая каждую строку, которую читаете.
- Закрываете файл.
Помня об этом, я рассмотрю каждую использованную здесь функцию для работы с файлами.
Выбор за вами
PHP не испытывает недостатка в эффективных способах чтения и анализа файлов. Классические функции, такие как fread , могут надежно служить вам большую часть времени, или же вас может больше привлечь простота readfile , если это необходимо для выполнения задачи. Выбор, на самом деле, зависит от того, что вы пытаетесь выполнить.
Если вы обрабатываете большие объемы данных, вероятно, fscanf окажется более полезной и эффективной, чем, скажем, использование file в сочетании с последующими командами split и sprintf . Если же вы просто отображаете текст большого объема с незначительными изменениями, напротив, использование функций file , file_get_contents , или readfile , возможно, будет более целесообразным. Это решение, вероятно, будет верным при использовании PHP для кэширования или даже создания временного прокси сервера.
PHP предоставляет множество инструментов для работы с файлами. Познакомьтесь ближе с каждым из них и узнайте, какие средства оптимально подходят для проекта, над которым вы работаете. Вам предлагается широкий выбор программных средств, используйте их наиболее эффективно и получайте удовольствие, обрабатывая ваши файлы средствами PHP.
Стандартные библиотеки PHP умеют генерировать только целые случайные числа. Однако, возникают задачи где нужно не целое рандомное число с максимально…
Ещё одна интересная статья на тему докера с примерами использования docker-compose для автоматического развёртывания всей экосистемы проекта. Поможет быстро структурировать…
Иногда при обработке с помощью PHP больших и не очень данных, можно словить досадную ошибку посреди выполнения скрипта: PHP Fatal…
Указатель на файл должен быть корректным и указывать на файл, успешно открытый функциями fopen() или fsockopen() (и всё ещё не закрытый функцией fclose() ).
Функция fpassthru
Вне зависимости от того, как вы считываете данные из файла, вы можете вывести оставшиеся данные на печать, используя стандартный канал вывода информации, посредством функции fpassthru .
Эта функция выводит данные на печать, поэтому вам не нужно помещать их в переменную.
Список изменений
Версия | Описание |
---|---|
4.3.0 | fgets() теперь безопасна для обработки бинарных данных |
Читайте также: