我想删除一个大文件(>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. a 2. b 3. c 4. d 5. e 删除该行后的文件可能如下所示
1. a 2. b 3. d 4. e 5. e 我想过通过$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);
}