Как использовать PHP для удаления X строк из начала текстового файла?

Я пишу PHP-скрипт, и скрипт выводит простой текстовый файл журнала операций, которые он выполняет. Как использовать PHP для удаления первых нескольких строк из этого файла, когда он достигнет определенного размера файла?

В идеале, я хотел бы сохранить первые две строки (дата/время создания и пустой) и начать удаление из строки 3 и удалить x количество строк. Я уже знаю о filesize() функция, поэтому я буду использовать это, чтобы проверить размер файла.

пример текст журнала:

*** LOG FILE CREATED ON 2008-10-18 AT 03:06:29 ***

2008-10-18 @ 03:06:29  CREATED: gallery/thumbs
2008-10-18 @ 03:08:03  RENAMED: gallery/IMG_9423.JPG to gallery/IMG_9423.jpg
2008-10-18 @ 03:08:03  RENAMED: gallery/IMG_9188.JPG to gallery/IMG_9188.jpg
2008-10-18 @ 03:08:03  RENAMED: gallery/IMG_9236.JPG to gallery/IMG_9236.jpg
2008-10-18 @ 03:08:03  RENAMED: gallery/IMG_9228.JPG to gallery/IMG_9228.jpg
2008-10-18 @ 03:08:03  RENAMED: gallery/IMG_3104.JPG to gallery/IMG_3104.jpg
2008-10-18 @ 03:08:03  RENAMED: gallery/First dance02.JPG to gallery/First dance02.jpg
2008-10-18 @ 03:08:03  RENAMED: gallery/BandG02.JPG to gallery/BandG02.jpg
2008-10-18 @ 03:08:03  RENAMED: gallery/official03.JPG to gallery/official03.jpg
2008-10-18 @ 03:08:03  RENAMED: gallery/Wedding32.JPG to gallery/Wedding32.jpg
2008-10-18 @ 03:08:03  RENAMED: gallery/Gettaway car16.JPG to gallery/Gettaway car16.jpg
2008-10-18 @ 03:08:04  CREATED: gallery/thumbs/Afterparty05.jpg
2008-10-18 @ 03:08:04  CREATED: gallery/thumbs/IMG_9254.jpg
2008-10-18 @ 03:08:04  CREATED: gallery/thumbs/IMG_9175.jpg
2008-10-18 @ 03:08:04  CREATED: gallery/thumbs/official05.jpg
2008-10-18 @ 03:08:04  CREATED: gallery/thumbs/First dance01.jpg
2008-10-18 @ 03:08:04  CREATED: gallery/thumbs/Wedding29.jpg
2008-10-18 @ 03:08:04  CREATED: gallery/thumbs/men walking.jpg

9 ответов


$x_amount_of_lines = 30;
$log = 'path/to/log.txt';
if (filesize($log) >= $max_size)) {
  $file = file($log);
  $line = $file[0];
  $file = array_splice($file, 2, $x_amount_of_lines);
  $file = array_splice($file, 0, 0, array($line, "\n")); // put the first line back in
  ...
}

изменить: с коррекцией от rcar и сохранением первой строки.


используйте SPL, Luke

PHP 5 поставляется с большим количеством итераторов goodness:

<?php

$line_to_strip = 5;
$new_file = new SplFileObject('test2.log', 'w');

foreach (new LimitIterator(new SplFileObject('test.log'), $line_to_strip) as $line)
    $new_file->fwrite($line);    

?>

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


Это учебник проблемы файлы журнала, и я хотел бы предложить другое решение.

проблема с подходом "удаление строк в начале файлов" заключается в том, что добавление новых строк становится чрезвычайно медленным, как только ему приходится удалять первые строки для каждой новой строки, которую он пишет.

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

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

Это можно представить как парковка автомобилей на линию с места на 50. Парковка первые 50 автомобилей быстро, просто ездить позади автомобиля перед и сделано. Но когда вы приходите к 50, и автомобиль спереди (начало файла) должен быть удален, вы должны водить 2-й автомобиль в 1-й положение, от 3-го до 2-го и так далее, прежде чем вы сможете въехать с последним автомобилем на 50-й позиции. (И это нужно повторить для новый автомобиль, который вы хотите парке!)

мое предложение вместо этого сохраняет в разные файлы журнала, datewise, а затем сохраняет максимум 30 дней назад и т. д. Таким образом, воспользовавшись файловой системой, которая уже отлично решила эту проблему.


можно использовать file () функция для чтения файла в массив строк, а затем использовать array_slice () чтобы удалить первые X строк.

$X = 100; // Number of lines to remove

$lines = file('log.txt');
$first_line = $lines[0];
$lines = array_slice($lines, $X + 2);
$lines = array_merge(array($first_line, "\n"), $lines);

// Write to file
$file = fopen('log.txt', 'w');
fwrite($file, implode('', $lines));
fclose($file);

Если вы можете запустить команду linux, попробуйте split. Это позволяет разделить по количеству строк, чтобы сделать вещи легко.

в противном случае, я думаю, вам придется прочитать его и записать в 2 других файла.


вместо @Грега ответ, вы можете прочитать весь файл в массив, пропустить первые X много записей, а затем переписать массив в файл.

Как подход:http://us3.php.net/manual/en/function.file-get-contents.php

$fle = file_get_contents("filename");
// skip X many newlines, overwriting the contents of the string with ""
// http://us3.php.net/manual/en/function.file-put-contents.php
file_put_contents("filename", $fle);

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

в псевдокоде:

open original file IN for reading
create new output file OUT
read the first two lines from IN
write these lines to OUT
for each line to skip:
    read a line from IN
for the remainder of the file:
    read a line from IN
    write the line to OUT
close IN
close OUT
delete IN
rename OUT to IN

преимущество этого метода над другими представил, что это не требуется сначала прочитать весь файл в память. Вы не упомянули, насколько велик ваш верхний предел размера, но если это что-то вроде 100 МБ, вы можете обнаружить, что загрузка файла в память не является приемлемым использованием пространства.


вот готовую функцию

<?php
//--------------------------------
// FUNCTION TO TRUNCATE LOG FILES
//--------------------------------
function trim_log_to_length($path,$numHeaderRows,$numRowsToKeep){
    $file = file($path);
    $headerRows = array_slice($file,0,$numHeaderRows);
    // if this file is long enough were we should be truncating it
    if(count($file) - $numRowsToKeep > $numHeaderRows){
        // figure out the rows we wanna keep
        $dataRowsToKeep = array_slice($file,count($file)-$numRowsToKeep,$numRowsToKeep);
        // write the file
        $newFileRows = array_merge($headerRows,$dataRowsToKeep);
        file_put_contents($path, implode($newFileRows));
    }
}
?>

следующий код поможет вам удалить количество строк от начала файла

$content = file('file.txt');
array_splice($content, 0, 5); // this line will delete first 5 lines //change asper your requirement  
file_put_contents('file.txt', $content);