2015-09-03 3 views
4

Я пытаюсь удалить строку из середины большого файла. (> 20 МБ). Я знаю позицию в файле начала строки, которую нужно удалить.Удаление строки из середины большого файла php

Вот что у меня есть.

/** 
* 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. с
  3. д
  4. е

Файл после удаления строки может выглядеть

  1. б
  2. d
  3. е
  4. е

Я думал о том-то обрезки конец основного файла на величину $ 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); 
} 
+0

Возможный дубликат [Как удалить некоторую строку из текстового файла с помощью PHP?] (Http://stackoverflow.com/questions/14250773/how-to-remove-some-line-from-text-file-using- php) – cmorrissey

+1

Файл имеет> 200 000 строк и может содержать> 400 000. Я чувствую, что загрузка всего файла в массив (память) будет довольно неэффективной. Вот почему я попробовал вышеуказанный подход, но столкнулся с этой проблемой. – user4775085

ответ

1

Я думаю, вы очень близки к решению.

Я бы прилипают к вашей идее удаления $lengthRemoved с конца файла и предложил бы использовать ftruncate($handle, $size); перед fclose(), где это размер, чтобы обрезать до (размер = originalFilesize - lengthRemoved).

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

+0

Спасибо! Это была функция, которую я искал. – user4775085

+0

Рад, что я мог помочь :) –

1

Поскольку ваш файл очень большой вы можете использовать команду sed если ваш PHP установки позволит использовать эту функцию с помощью exec.

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

Если 3 указывает нужный номер строки.

Смежные вопросы