Главное меню

Другие полезные файловые функции

Существует ряд других файловых функций, которые иногда могут оказаться полезными.

Проверка, существует ли файл: функция file_exists ()

Если необходимо проверить, существует ли тот или иной файл, не открывая его, можно воспользоваться функцией file_exists (), как показано в следующем примере:

if (file_exists ("$DOCUMENT_ROOT/ . ./orders/orders.txt") ) {

echo 'Имеются заказы, ожидающие обработки.';

} else {

echo 'В настоящий момент заказов нет.';

}

Выяснение размера файла: функция filesize ()

Размер файла можно определить с помощью функции filesize ():

echo filesize("$DOCUMENT_ROOT/../orders/orders.txt");

Она возвращает размер файла, выраженный в байтах. Эта функция может применяться в сочетании с функцией fread () для считывания всего файла (или некоторой его части). Весь разработанный нами выше сценарий можно заменить следующим кодом:

$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'rb');

echo nl2br(fread( $fp, filesize("$DOCUMENT_ROOT/../orders/orders.txt" )));

fclose($fp);

Функция nl2br() преобразовывает при выводе символы \п на HTML-дескрипторы <br />.

Удаление файла: функция unlink ()

Если после обработки заказов файл заказов должен быть удален, это можно сделать с помощью функции unlink (). (Функции с именем delete не существует.) Например:

unlink("$DOCUMENT_ROOT/../orders/orders.txt");

Эта функция возвращает значение false, если файл не может быть удален. Как правило, это происходит при недостаточном уровне прав доступа к файлу или если файл вообще не существует.

Перемещение внутри файла: функции rewind (), fseek() и ftell ()

Проверять и манипулировать позицией внутри указателя файла можно с помощью функций rewind (), fseek () и ftell ().

Функция rewind () переустанавливает указатель файла на начало файла. Функция ftell () сообщает в байтах позицию указателя относительно начала файла. Например, в нижнюю часть первоначального сценария (перед командой fclose ()) можно поместить следующие строки:

echo 'Конечная позиция в указателе файла: ' . (ftell($fp));

echo ' <br />';

rewind($fp);

echo 'Позиция после вызова функции rewind (): '.(ftell($fp));

echo '<br />';

Вывод в окне браузера будет выглядеть аналогично показанному на рис. 2.5.

Перемещение внутри файла

Функция fseek () может использоваться для установки указателя файла в некоторую конкретную точку внутри файла. Ее прототип имеет вид:

int fseek (resource fp, int offset) [, int whence] ;

В результате вызова функции fseek () указатель файла fp устанавливается в точку файла, имеющую смещение offset байт относительно позиции, заданной параметром whence (откуда). Необязательный параметр whence по умолчанию принимает значение SEEK_SET, которое фактически означает начало файла. Другими возможными значениями являются SEEK_CUR (текущее положение указателя файла) и SEEK_END (конец файла).

Вызов функции rewind() эквивалентен вызову функции fseek() со смещением, равным нулю. Например, вы можете использовать функцию fseek() с целью нахождения средней записи в файле или для реализации бинарного поиска. Часто, когда подобные задачи требуется решать применительно к достаточно сложному файлу данных, имеет смысл отдать предпочтение базам данных.

Блокирование файлов

Представьте ситуацию, когда два клиента одновременно пытаются заказать товар. (Эта ситуация возникает не столь уж редко, особенно когда веб-сайт начинает обрабатывать трафик существенного объема.) Что произойдет, если один клиент вызовет функцию fopen () и начнет запись, а затем второй клиент также вызовет функцию fopen () и тоже предпримет попытку записи? Каким в результате всего этого окажется содержимое файла? Будет ли вначале записан первый заказ, а затем второй, или наоборот? Будет ли записан первый заказ или второй? Либо же содержимое будет представлять собой нечто практически бесполезное вроде смеси двух заказов? Ответы на эти вопросы зависят от конкретной используемой операционной системы, но чаще всего точно ответить на них невозможно.

Во избежание подобных проблем используется механизм блокирования файлов. В РНР блокирование реализуется с помощью функции flock(). Эта функция должна вызываться после открытия файла, но перед считыванием данных из этого файла или их записью в этот файл.

Прототип функции flock () выглядит следующим образом:

bool flock(resource fp, int operation [, int &wouldblock]);

В функцию необходимо передать указатель на открытый файл и константу, представляющую вид требуемой блокировки. Функция возвращает значение true, если блокировка была успешно выполнена, и false – в противном случае. Необязательный третий параметр должен содержать true, если запрашиваемая блокировка может привести к блокированию текущего процесса (т.е. к его ожиданию).

Возможные значения параметра operation (операция) перечислены в табл. 2.2. Эти возможные значения претерпели некоторые изменения в версии РНР 4.0.1, поэтому в упомянутой таблице представлены оба набора значений.

Блокирование файлов

Если вы намереваетесь воспользоваться функцией flock (), ее следует включить во все сценарии, в которых задействуется данный файл; в противном случае ее применение лишено смысла.

Обратите внимание на то, что функция flock () не работает с системой NFS (Network File System – сетевая файловая система) и другими сетевыми файловыми системами. Она также не работает с устаревшими файловыми системами, которые не поддерживают такую блокировку, например, FAT (File Allocation Table – таблица размещения файлов). В среде некоторых операционных систем она реализована на уровне процессов и не будет работать корректно, если вы используете API (Application Programming Interface – интерфейс программирования приложений) многопоточного сервера.

Для использования блокировки в рассматриваемом примере сценарий processorder .php необходимо изменить:

$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'ab');

flock($fp, LOCK_EX); // блокирование файла для записи

fwrite($fp, $outputstring);

flock($fp, LOCK_UN); // снятие блокировки на запись

fclose($fp);

Также потребуется добавить блокировки в сценарий vieworders.php:

$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'r');

flock($fp, LOCK_SH); // блокирование файла для чтения

// чтение из файла

flock($fp, LOCK_UN); // снятие блокировки на чтение

fclose ($fр);

Теперь код стал более надежным, тем не менее, он все еще не идеален. Что произойдет, если два сценария попытаются одновременно запросить блокировку? Это привело бы к состоянию состязаний, когда процессы соперничают за установку блокировки, в условиях которого неизвестно, какому из них это удастся, что, в свою очередь, могло бы породить новые проблемы. Значительно больший эффект можно достичь при использовании одной из систем управления базами данных.

Системы управления базами данных

До сих пор во всех рассмотренных примерах использовались двумерные файлы. Далее будет рассматриваться применение MySQL, одной из широко известных систем управления реляционными базами данных. “А зачем все это нужно?” – спросите вы.

Проблемы, связанные с использованием двумерных файлов:

При работе с двумерными файлами возникает ряд проблем.

■ Когда двумерные файлы становятся большими, работа с ними существенно замедляется.

■ Поиск конкретной записи или группы записей в двумерном файле затруднен. Если эти записи упорядочены, для поиска по ключевому полю можно использовать какой-либо из видов бинарного поиска в сочетании с применением записей фиксированной длины. Если нужно найти информацию, соответствующую определенному шаблону (например, найти всех клиентов, проживающих в Жмеренке), придется прочесть и проверить каждую из записей по отдельности.

■ Решение задачи одновременного доступа может оказаться проблематичным. Уже было показано, как блокируются файлы, но это может привести к возникновению описанного выше состояния состязаний. Кроме того, это может привести к образованию “узкого места” в системе. При достаточно интенсивном трафике на сайте большой группе пользователей, возможно, придется долго ждать разблокирования файла, прежде чем они смогут разместить свои заказы. Если ожидание продлится слишком долго, люди обратятся за покупкой куда-нибудь в другое место.

■ Вся рассмотренная до сих пор обработка файлов сводилась к последовательной обработке, по условиям которой считывание начиналось с начала файла и выполнялось до его конца. При необходимости вставить записи или удалить их из середины файла (т.е. при необходимости реализации произвольного доступа), это может оказаться затруднительным – т.к. придется прочитать весь файл в память, внести в него необходимые изменения и снова записать весь файл. При работе с крупными файлами данных этот процесс сопряжен с существенными накладными расходами.

■ Помимо ограничений, налагаемых правами доступа к файлам, не существует мало-мальски приемлемого способа обеспечения различных уровней доступа к данным.

Как эти проблемы устраняются с помощью систем управления реляционными базами данных:

Системы управления реляционными базами данных (СУРБД) успешно решают все эти проблемы.

■ СУРБД могут обеспечить более быстрый доступ к данным, чем двумерные файлы. При этом MySQL – система управления базами данных, описываемая здесь – обладает одними из самых высоких показателей производительности среди всех СУРБД.

■ В СУРБД можно легко реализовать запрос на извлечение наборов данных, соответствующих определенным критериям.

■ СУРБД обладают встроенными механизмами обработки параллельных обращений, освобождая программиста от этой обязанности.

■ СУРБД обеспечивают произвольный доступ к данным.

■ СУРБД обладают встроенными системами определения прав доступа. MySQL обладает особенно большими возможностями в этой области.

Возможно, главная причина использования СУРБД состоит в том, что все или, по меньшей мере, большинство функциональных возможностей, которыми, по всеобщему мнению, должны обладать системы хранения данных, в ней уже реализованы.