Я пишу 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
$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 ... }
edit: с исправлением от rcar и сохранением первой строки.
PHP 5 поставляется с большим количеством итераторов добра:
<?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. Это не проблема, если лимит размера файла журнала очень мал или если он написан на неактивном, но с большим количеством записей (как в случае с файлами журналов), такую же огромную операцию нужно выполнять много раз что приводит к серьезным недостаткам производительности.
Это можно представить как парковочные автомобили на линии с пространством на 50. Парковка первых 50 автомобилей – это быстро, просто заезжайте за автомобилем и сделайте это. Но когда вы дойдете до 50, и автомобиль впереди (начало файла) должен быть удален, вам нужно довести 2-й автомобиль до 1-й позиции, 3-й и 2-й и так далее, прежде чем вы сможете водить машину с последний автомобиль на 50-й позиции. (И это нужно повторять для каждого нового автомобиля, который вы хотите припарковать!)
Мое предложение вместо этого сохраняет в разные файлы журнала, по дате, а затем сохраняет максимум 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 других файла.
В качестве альтернативы ответом @ Greg вы можете прочитать весь файл в массиве, пропустить первый 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);