代码之家  ›  专栏  ›  技术社区  ›  PHLAK

如何使用PHP删除文本文件开头的x行数?

  •  6
  • PHLAK  · 技术社区  · 16 年前

    我正在编写一个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 回复  |  直到 7 年前
        1
  •  4
  •   bbxbby    16 年前
    $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更正并保存第一行。

        2
  •  20
  •   Bite code    16 年前

    使用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。

        3
  •  4
  •   community wiki Hannes Landeholm    16 年前

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

    “在文件开头删除行”方法的问题是,添加新行的速度会非常慢,一旦它必须删除正在写入的每一行的第一行。

    普通的日志文件附加只需要在文件系统中的文件末尾再写几个字节(有时还需要分配一个新的扇区,这会导致大量的碎片——为什么日志文件通常是这样)。

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

    这可以想象成在一条50人的线上停车。前50辆车停车很快,只要在车后面向前开就行了。但是当你到了50岁,前面的车(文件开头)必须被移走,你必须把第二辆车开到第一位,第三辆到第二辆等等,然后你才能把最后一辆车开到第50位。(这必须重复 每一个 你想停车的新车!)

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

        4
  •  2
  •   Paige Ruten    16 年前

    你可以用 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
  •  0
  •   Darryl Hein IrishChieftain    16 年前

    如果可以运行Linux命令,请尝试 split . 它允许您按行数进行拆分,以使操作更简单。

    否则,我想你得把它读进去,然后写到另外两个文件里。

        6
  •  0
  •   Community CDub    8 年前

    或者 @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);
    
        7
  •  0
  •   Greg Hewgill    16 年前

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

    在伪代码中:

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

        8
  •  0
  •   ummdorian    7 年前

    这里有一个随时可用的功能

    <?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));
        }
    }
    ?>
    
        9
  •  0
  •   Darshan Jadiye    7 年前

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

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