【问题标题】:How to use PHP to delete X number of lines from the beginning of a text file?如何使用 PHP 从文本文件的开头删除 X 行?
【发布时间】:2010-09-17 23:17:57
【问题描述】:

我正在编写一个 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

【问题讨论】:

    标签: php file logging


    【解决方案1】:

    使用 SPL,卢克

    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。

    【讨论】:

    • 此解决方案写入新文件,但问题询问有关编辑文件。
    【解决方案2】:
    $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 进行更正并保存第一行。

    【讨论】:

    • 你可能想要 > $max_size 而不是 ==
    【解决方案3】:

    这是一个日志文件的教科书问题,我想提出另一种解决方案。

    “在文件开头删除行”方法的问题在于,添加新行变得极其缓慢,一旦它必须删除它正在编写的每个新行的第一行。

    普通的日志文件附加只涉及在文件系统中的文件末尾写入更多字节(有时它必须分配一个新扇区,这会导致大量碎片 - 为什么日志文件通常是这样) .

    但这里最大的问题是,当您在每行写入的开头删除一行时。必须首先将整个文件读入内存,然后重写,从而导致硬盘驱动器的大量 I/O(相比之下)。更糟糕的是,由于 PHP 数组的性质,此处的“拆分为 PHP 数组并跳过第一行”解决方案极其缓慢。如果日志文件大小限制非常小或者不经常写入,这不是问题,但是写入很多(如日志文件的情况),同样巨大的操作必须执行很多次导致主要的性能缺陷。

    这可以想象为在一条可容纳 50 辆空间的线上停车。停放前 50 辆汽车很快,只需在前面的汽车后面开入即可。但是当你到了 50 并且前面的车(文件的开头)必须被移除时,你必须将第 2 辆车开到第 1 位,第 3 到第 2 等等,然后才能开车进入最后一辆车在第 50 位。 (对于您要停放的每辆辆新车,必须重复此操作!)

    我的建议是保存到不同的日志文件,按日期保存,然后最多存储 30 天等。从而利用文件系统,它已经很好地解决了这个问题。

    【讨论】:

    • 好主意,但对于我的特殊需求,这是不可接受的。我有一个小日志文件,可能不会经常/经常写入。但我会在以后的项目中记住这一点。
    【解决方案4】:

    您可以使用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);
    

    【讨论】:

      【解决方案5】:

      这是一个准备就绪的功能

      <?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));
          }
      }
      ?>
      

      【讨论】:

        【解决方案6】:

        如果您可以运行 linux 命令,请尝试split。它允许您按行数拆分以使事情变得简单。

        否则,我认为您必须将其读入并写入其他 2 个文件。

        【讨论】:

          【解决方案7】:

          替代@Greg's 答案,您可以将整个文件读入一个数组,跳过前 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);
          

          【讨论】:

          • 这样的问题是,根据写入的行数,日期/时间会乱序。此外,我预见文件会一遍又一遍地写入相同的行。
          • 是的,这可能是一个问题(重复写入相同的数据),具体取决于文件的大小 - 这肯定是一种蛮力方法 :) .. 为什么日期/时间会过期顺序?除非在 php 中读取文件时附加到,否则我认为您不会看到
          【解决方案8】:

          典型的操作系统不提供“就地”插入或删除文件内容的功能。您需要做的是编写一个读取第一个文件的函数,并创建一个 new 输出文件,其中包含您要保留的行。然后当你完成后,删除旧文件并将新文件重命名为旧名称。

          在伪代码中:

          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 MB,您可能会发现将文件加载到内存中是不可接受的空间使用。

          【讨论】:

            【解决方案9】:

            以下代码将帮助您删除文件开头的行数

            $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);
            

            【讨论】:

              猜你喜欢
              • 2011-08-30
              • 2020-10-31
              • 1970-01-01
              • 1970-01-01
              • 2011-03-16
              • 1970-01-01
              相关资源
              最近更新 更多