Считывание из файла
Уже сейчас клиенты компании “Автозапчасти от Вована” могут отправлять свои заказы через Интернет, однако если сотрудники компании Вована захотят просмотреть заказы, им придется открывать файлы самостоятельно.
Давайте создадим веб-интерфейс, который позволит служащим компании “Автозапчасти от Вована” легко читать файлы. Код такого интерфейса приведен в листинге 2.3.
В этом сценарии выполняется последовательность действий, которая упоминалась выше: открытие файла, чтение из файла, закрытие файла. Вывод, генерируемый этим сценарием с использованием файла данных из листинга 2.1, показан на рис. 2.4.
Теперь подробно рассмотрим функции, используемые в этом сценарии.
Открытие файла для чтения: функция fopen ()
И снова мы открываем файл с помощью функции fopen (). На этот раз файл открывается только для чтения, поэтому используется режим файла ' r':
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'rb');
Как узнать, где остановиться: функция feof ()
В этом примере мы используем цикл while для чтения из файла до тех пор, пока не будет достигнут конец файла. Цикл while проверяет, достигнут ли конец файла, с помощью функции feof ():
while (!feof ($fp))
Функция feof () принимает один параметр – дескриптор файла. Она возвращает значение true, если указатель файла находится в конце файла. И хотя имя функции может показаться странным, его легко запомнить, если знать, что feof означает File End Of File (“файл: конец файла”).
В данном случае (и вообще при чтении из файла) считывание продолжается до тех пор, пока не будет достигнут символ EOF.
Построчное чтение: функции fgets (), fgetss () и fgetcsv ()
В рассматриваемом примере для считывания из файла используется функция fgets ():
$order = fgets($fp, 999);
Эта функция используется для чтения из файла строк по одной за раз. В данном случае считывание будет выполняться до тех пор, пока не встретится символ новой строки (\n), символ EOF или из файла не будут прочитаны 998 байт. Максимальная длина считываемой строки равна указанной длине минус 1 байт.
Существует много различных функций, которые используют для чтения файлов. Функция fgets () полезна при работе с файлами, содержащими обычный текст, который требуется обрабатывать по частям.
Интересной разновидностью функции fgets () является функция fgetss (), имеющая следующий прототип:
string fgetss(resource fp, int length, string [allowable_tags] );
Эта функция во многом подобна функции fgets () и отличается от нее только тем, что она удаляет любые РНР- и HTML-дескрипторы, обнаруженные в строке.
Если вы хотите сохранить в файле какие-то конкретные дескрипторы, их следует поместить в строку разрешенных дескрипторов allowable_tags. Функцию fgetss () следует использовать для достижения большей безопасности во время чтения файла, записанного кем-либо другим или содержащего данные, введенные пользователем. Включение в файл HTML-кода без каких-либо ограничений может привести к нарушению тщательно спланированного форматирования. Отсутствие ограничений на наличие в файле РНР-кода может предоставить злонамеренному пользователю практически полную свободу действий на вашем сервере.
Функция fgetcsv () представляет собой еще одну разновидность функции fgets (). Она имеет следующий прототип:
array fgetcsv(resource fp, int length [, string delimiter [, string enclosure]]) ;
Эта функция разбивает строки файлов при использовании некоторого символа в качестве разделителя, например, табуляции (как предлагалось ранее) или запятой (которая обычно применяется в электронных таблицах и других приложениях). Если требуется восстановить переменные заказа по отдельности, а не иметь дело со строкой текста, следует прибегнуть к услугам функции fgetcsv (). Она вызывается примерно так же, как и функция fgets (), но ей необходимо передать разделитель, который служит разделителем полей. Например, оператор
$order = fgetcsv($fp, 100, "\t");
извлекает строку из файла и разделяет ее при каждом обнаружении символа табуляции (\t). Полученные при этом строки помещаются в массив (в данном примере это массив $order).
Параметр длины length должен быть больше длины самой длинной строки считываемого файла, выраженной в символах.
Параметр вложения enclosure используется для описания символов, в которые заключаются каждое поле в строке. Если эти символы не заданы, по умолчанию принимается символ " (двойные кавычки).
Чтение всего файла: функции readfile (), fpassthru () и file ()
Вместо чтения по одной строке из файла за раз можно прочитать весь файл как единое целое. Существуют четыре способа выполнения такого считывания.
Первый способ предусматривает использование функции readfile (). Весь приведенный выше сценарий можно заменить одной строкой:
readfile("$DOCUMENT_ROOT/../orders/orders.txt");
Обращение к функции readfile () открывает файл, отображает его содержимое в стандартном выводе (окне браузера), а затем закрывает файл. Прототип этой функции readfile () выглядит следующим образом:
int readfile(string filename[, int use_include_path[, resource context]]);
Необязательный второй параметр use_include_path указывает, должен ли РНР при поиске файла использовать путь, хранящийся в include_path, и действует так же, как и в функции fopen (). Третий необязательный параметр context используется, только если файл открыт удаленно, например, через HTTP. Функция readfile () возвращает общее количество байт, считанных из файла.
Второй способ предполагает применение функции fpassthru (). Сначала необходимо открыть файл с помощью функции fopen (). Затем можно передать указатель файла в функцию fpassthru (), которая загрузит содержимое файла, начиная с позиции, заданной указателем, в стандартный вывод. По окончании этой операции функция закрывает файл. Представленный выше сценарий можно заменить функцией fpassthru () следующим образом:
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'rb');
fpassthru ($fp);
Функция fpassthru () возвращает значение true, если чтение прошло успешно, и false – в противном случае.
Третья возможность считывания всего файла предусматривает использование функции file (). Эта функция идентична функции readfile () за исключением того, что вместо отображения файла в стандартном выводе она преобразует его в массив. Более подробно данная функция будет рассматриваться во время изучения массивов. А пока просто отметим, что эту функцию можно вызвать следующим образом:
$filearray = file("$DOCUMENT_ROOT/../orders/orders.txt");
Эта строка приведет к считыванию всего файла в массив с именем $filearray. Каждая строка файла сохраняется в отдельном элементе этого массива. Обратите внимание, что эта функция не является безопасной в отношении бинарных файлов в устаревших версиях РНР.
В качестве четвертого варианта можно воспользоваться функцией file_get_contents (). Эта функция идентична функции readfile () за исключением того, что она возвращает содержимое файла в виде строки вместо того, чтобы выводить его в окно браузера.
Чтение символа: функция fgetc ()
Еще одна возможность обработки файлов состоит в чтении из файла по одному символу за раз. Это реализуется с помощью функции fgetc () (“file get character” – “получить символ из файла”). В качестве своего единственного параметра она принимает указатель файла и возвращает следующий символ из файла. Цикл while в нашем первоначальном сценарии можно заменить циклом, в котором используется функция fgetc():
while (!feof($fр)) {
$char = fgetc ($fp);
if (!feof($fp))
echo ($char=="\n" ? "<br />" : $char) ;
}
С помощью функции fgetc () этот код считывает из файла по одному символу за раз и сохраняет его в переменной $char, пока не будет достигнут конец файла. Затем выполняется небольшая дополнительная обработка с целью замены текстовых символов конца строки \п HTML-разделителями строк <br />.
Это делается лишь для хорошего форматирования. Если попытаться вывести файл в браузере с символами новой строки между записями, весь файл будет представлен в виде одной строки. (Попытайтесь сделать это и посмотрите, что получится.) Веб-браузеры не отображают пробельные символы наподобие символов новой строки, поэтому они должны заменяться HTML-дескрипторами, в частности, <br />. Для изящного решения данной задачи используется тернарная операция.
Незначительный побочный эффект использования функции fgetc() вместо функции fgets () заключается в том, что fgetc () будет возвращать символ EOF, в то время как fgets () этого не делает. После чтения символа приходится снова проверять feof (), поскольку символ EOF в окне браузера отображаться не должен.
В общем случае считывание файла символ за символом не оправдано, если только по какой-либо особой причине не требуется посимвольная обработка файла.
Чтение строк произвольной длины: функция fread()
Последний способ чтения из файла предусматривает использование функции fread (), которая читает из файла произвольное количество байт. Эта функция имеет следующий прототип:
string fread(resource fp, int length);
Функция считывает length байт или все байты до конца файла – в зависимости от того, что произойдет раньше.
|