从大文件php的中间删除一行

时间:2015-09-03 16:53:12

标签: php file

我正在尝试从大文件的中间删除一行。 (> 20MB)。我知道要删除的行开头的文件中的位置。

这是我现在拥有的。

/**
 * Removes a line at a position from the file
 * @param  [int] $position  The position at the start of the line to be removed
 */
public function removeLineAt($position)
{
    $fp = fopen($this->filepath, "rw+");
    fseek($fp, $position);

    $nextLinePosition = $this->getNextLine($position, $fp);
    $lengthRemoved = $position - $nextLinePosition;
    $fpTemp = fopen('php://temp', "rw+");

    // Copy the bottom half (starting at line below the line to be removed)
    stream_copy_to_stream($fp, $fpTemp, -1, $nextLinePosition);

    // Seek to the start of the line to be removed
    fseek($fp, $position);
    rewind($fpTemp);

    // Copy the bottom half over the line to be removed
    stream_copy_to_stream($fpTemp, $fp);        

    fclose($fpTemp);
    fclose($fp);
}

但是,虽然上面的代码确实从文件中删除了该行;因为临时文件比原始文件短。原始文件的尾端仍然存在并加倍。

例如: 原始文件是

  1. 一个
  2. B'/ LI>
  3. C
  4. d
  5. ë
  6. 删除行后的文件可能看起来像

    1. 一个
    2. B'/ LI>
    3. d
    4. ë
    5. ë
    6. 我已经想过以某种方式通过$ lengthRemoved量来修剪主文件的结尾但是我想不出一个简单的方法来做到这一点。

      有什么建议吗?

      • 注意:该文件具有> 200,000行,有时> 300,000。我觉得好像将整个文件加载到一个数组(内存)中会非常低效。这就是为什么我尝试了上述方法但遇到了一个问题

      对于那些正在寻找答案的人来说,这是我提出的最终功能,感谢您的帮助!修改它以满足您的需求。

      /**
       * Removes a line at a position from the file
       * @param  [int] $position  The position at the start of the line to be removed
       */
      public function removeLineAt($position)
      {
          $fp = fopen($this->filepath, "rw+");
          fseek($fp, $position);
      
          $nextLinePosition = $this->getNextLine($position, $fp);
          $lengthRemoved = $position - $nextLinePosition;
          $fpTemp = fopen('php://temp', "rw+");
      
          // Copy the bottom half (starting at line below the line to be removed)
          stream_copy_to_stream($fp, $fpTemp, -1, $nextLinePosition);
      
          // Remove the difference
          $newFileSize = ($this->totalBytesInFile($fp) + $lengthRemoved);
          ftruncate($fp, $newFileSize);
      
          // Seek to the start of the line to be removed
          fseek($fp, $position);
          rewind($fpTemp);
      
          // Copy the bottom half over the line to be removed
          stream_copy_to_stream($fpTemp, $fp);        
      
          fclose($fpTemp);
          fclose($fp);
      }
      

2 个答案:

答案 0 :(得分:1)

我认为你非常接近解决方案。

我会坚持你从文件末尾删除$lengthRemoved的想法,并建议在ftruncate($handle, $size);之前使用fclose(),其中size是要截断的大小( size = originalFilesize - lengthRemoved)。

http://www.php.net/manual/en/function.ftruncate.php

答案 1 :(得分:1)

由于您的文件非常大,如果您的php安装允许您使用该功能,您可能希望通过sed使用exec命令。

exec("sed '3d' fileName.txt");

3表示所需的行号。