Удаление из файла последней строки

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

Решение
Если файл маленький, то можно прочитать его в массив с помощью функции file(), а затем удалить последний элемент массива:

$lines = file('employees.txt');
array_pop($lines);
$file = join('',$lines);

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

$fh = fopen('employees.txt','r') or die("can't open: $php_errormsg");
$linebreak = $beginning_of_file = 0;
$gap = 80;
$filesize = filesize('employees.txt');
fseek($fh,0,SEEK_END);
while (! ($linebreak || $beginning_of_file)) {
// записываем в то место файла, где находимся
$pos = ftell($fh);
/* возвращаемся на $gap символов, вызываем функцию rewind(),
* чтобы перейти в начало, если мы находимся в позиции
* меньше $gap символов от начала файла */
if ($pos < $gap) {
rewind($fh);
} else {
fseek($fh,-$gap,SEEK_CUR);
}
// читаем $gap символов, которые мы только что нашли, двигаясь назад
$s = fread($fh,$gap) or die($php_errormsg);
/* если мы читаем по направлению к концу файла,
* то удаляем последний символ, так как если это символ
* новой строки, то мы должны игнорировать его */
if ($pos + $gap >= $filesize) {
$s = substr_replace($s,'',-1);
}// переходим обратно на то место, где мы были до чтения $gap символов в $s
if ($pos < $gap) {
rewind($fh);
} else {
fseek($fh,-$gap,SEEK_CUR);
}
// присутствует ли в $s символ конца строки?
if (is_integer($lb = strrpos($s,"\n"))) {
$linebreak = 1;
// новая строка файла начинается сразу за символом конца строки
$line_end = ftell($fh) + $lb + 1;
}
// выходим из цикла, если мы находимся в начале файла
if (ftell($fh) == 0) { $beginning_of_file = 1; }
}
if ($linebreak) {
rewind($fh);
$file_without_last_line = fread($fh,$line_end) or die($php_errormsg);
}
fclose($fh) or die("can't close: $php_errormsg");

Эта программа начинает с конца файла и перемещается в обратном направлении порциями по $gap символов в поисках символа новой строки.


Найдя его, она узнает последнюю строку файла, которая начинается сразу после символа новой строки. Эта позиция сохраняется в переменной $line_end. После цикла while, если переменная $linebreak установлена, содержимое файла от начала до $line_end читается в переменную $file_without_last_line.

Последний символ файла игнорируется, поскольку если это символ новой строки, то он не означает начало последней строки файла. Рассмотрим 10-символьный файл, содержимое которого состоит из символов asparagus\n. В нем только одна строка, состоящая из слова asparagus и символа новой строки. Без своей последней строки этот файл пуст, о чем и сообщит предыдущая программа. Если бы она начала сканирование с последнего символа, то увидела бы символ новой строки и вышла бы из цикла сканирования, неправильно выведя строку asparagus без символа новой строки..



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

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

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