Подсчет строк, абзацев или записей в файле

Задача
Необходимо определить количество строк, абзацев или записей в файле.

Решение
Для подсчета строк применяется функция fgets(). Она читает одну строку за раз, поэтому нетрудно подсчитать, сколько раз она вызывается, пока не достигнут конец файла:

$lines = 0;
if ($fh = fopen('orders.txt','r')) {
while (! feof($fh)) {
if (fgets($fh,1048576)) {
$lines++;
}
}
}
print $lines;

Чтобы подсчитать абзацы, увеличивайте счетчик только при чтении пустой строки:

$paragraphs = 0;
if ($fh = fopen('great-american-novel.txt','r')) {
while (! feof($fh)) {
$s = fgets($fh,1048576);
if (("\n" == $s) || ("\r\n" == $s)) {
$paragraphs++;
}
}
}
print $paragraphs;

Для подсчета записей увеличивайте счетчик, только когда прочитанная строка содержит разделитель записей и пробельный символ:

$records = 0;
$record_separator = '--end--';
if ($fh = fopen('great-american-novel.txt','r')) {
while (! feof($fh)) {
$s = rtrim(fgets($fh,1048576));
if ($s == $record_separator) {
$records++;
}
}
}
print $records;

Обсуждение
В счетчике строк переменная $lines увеличивает свое значение, только если функция fgets() возвращает истинное значение.


Так как fgets() проходит по всему файлу, она возвращает каждую строку, которую извлекает. Достигнув последней строки, функция возвращает значение false, поэтому переменная $lines не получает неправильного приращения. Одновременно в файле будет достигнут EOF, поэтому feof() возвращает true, и цикл while завершается.

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

Пример 18.1. pc_split_paragraphs()
function pc_split_paragraphs($file,$rs="\r?\n") {
$text = join('',file($file));
$matches = preg_split("/(.*?$rs)(?:$rs)+/s",$text,-1,
PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
return $matches;
}

Содержимое файла разбивается на две или более строк, заканчивающихся символами новой строки, и возвращается в массиве $matches.

Разделяющее записи регулярное выражение по умолчанию, \r?\n, определяет разделители строк и в Windows, и в UNIX.


Если же файл слишком большой, то для того чтобы прочитать его в память за один раз, вызовите функцию pc_split_paragraphs_largefile(), показанную
в примере 18.2, которая читает файл порциями по 4 Кбайт.

Пример 18.2. pc_split_paragraphs_largefile()
function pc_split_paragraphs_largefile($file,$rs="\r?\n") {
global $php_errormsg;$unmatched_text = '';
$paragraphs = array();
$fh = fopen($file,'r') or die($php_errormsg);
while(! feof($fh)) {
$s = fread($fh,4096) or die($php_errormsg);
$text_to_split = $unmatched_text . $s;
$matches = preg_split("/(.*?$rs)(?:$rs)+/s",$text_to_split,-1,
PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
// если последняя порция не заканчивается двумя разделителями
// записи, то сохраните ее, чтобы разместить ее в начале
// следующей прочитанной части
$last_match = $matches[count($matches)-1];
if (! preg_match("/$rs$rs\$/",$last_match)) {
$unmatched_text = $last_match;
array_pop($matches);
} else {
$unmatched_text = '';
}
$paragraphs = array_merge($paragraphs,$matches);
}
// если после чтения всех частей существует последняя порция, которая
// не заканчивается разделителем записи, то считаем это абзацем
if ($unmatched_text) {
$paragraphs[] = $unmatched_text;
}
return $paragraphs;
}

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


Когда она обнаруживает конец абзаца в порции, прочитанной из файла, она сохраняет оставшийся текст порции в переменной и размещает его в начале следующей читаемой порции. Таким образом, текст, не прошедший проверку, становится началом нового абзаца файла.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела PHP на эту тему:
Блокировка файла
Выбор случайной строки из файла
Запись в несколько файловых дескрипторов одновременно
Запись в стандартный поток вывода
Непосредственная модификация файла без временной копии

Вернуться в раздел: PHP / 18. Файлы