Это самый эффективный способ получить и удалить первую строку в файле? - PullRequest
14 голосов
/ 09 марта 2010

У меня есть скрипт, который при каждом вызове получает первую строку файла. Известно, что каждая строка имеет одинаковую длину (32 буквенно-цифровых символа) и оканчивается на «\ r \ n». После получения первой строки скрипт удаляет ее.

Это делается следующим образом:

$contents = file_get_contents($file));
$first_line = substr($contents, 0, 32);
file_put_contents($file, substr($contents, 32 + 2)); //+2 because we remove also the \r\n

Очевидно, что это работает, но мне было интересно, есть ли более разумный (или более эффективный) способ сделать это?

В моем простом решении я в основном читаю и переписываю весь файл, просто чтобы взять и удалить первую строку .

Ответы [ 10 ]

20 голосов
/ 28 января 2012

Я пришел с этой идеей вчера:

function read_and_delete_first_line($filename) {
  $file = file($filename);
  $output = $file[0];
  unset($file[0]);
  file_put_contents($filename, $file);
  return $output;
}
14 голосов
/ 09 марта 2010

Нет более эффективного способа сделать это, кроме как переписать файл.

12 голосов
/ 03 января 2014

Нет необходимости создавать второй временный файл или помещать весь файл в память:

if ($handle = fopen("file", "c+")) {             // open the file in reading and editing mode
    if (flock($handle, LOCK_EX)) {               // lock the file, so no one can read or edit this file 
        while (($line = fgets($handle, 4096)) !== FALSE) { 
            if (!isset($write_position)) {        // move the line to previous position, except the first line
                $write_position = 0;
            } else {
                $read_position = ftell($handle); // get actual line
                fseek($handle, $write_position); // move to previous position
                fputs($handle, $line);           // put actual line in previous position
                fseek($handle, $read_position);  // return to actual position
                $write_position += strlen($line);    // set write position to the next loop
            }
        }
        fflush($handle);                         // write any pending change to file
        ftruncate($handle, $write_position);     // drop the repeated last line
        flock($handle, LOCK_UN);                 // unlock the file
    }
    fclose($handle);
}
6 голосов
/ 24 апреля 2014

Это сместит первую строку файла, вам не нужно загружать весь файл в память, как вы делаете это с помощью функции 'file'. Может быть, для небольших файлов это немного медленнее, чем для «файла» (возможно, но я держу пари, что нет), но может без проблем управлять большими файлами.

$firstline = false;
if($handle = fopen($logFile,'c+')){
    if(!flock($handle,LOCK_EX)){fclose($handle);}
    $offset = 0;
    $len = filesize($logFile);
    while(($line = fgets($handle,4096)) !== false){
        if(!$firstline){$firstline = $line;$offset = strlen($firstline);continue;}
        $pos = ftell($handle);
        fseek($handle,$pos-strlen($line)-$offset);
        fputs($handle,$line);
        fseek($handle,$pos);
    }
    fflush($handle);
    ftruncate($handle,($len-$offset));
    flock($handle,LOCK_UN);
    fclose($handle);
}
4 голосов
/ 09 марта 2010

вы можете перебирать файл, вместо того, чтобы помещать их в память

$handle = fopen("file", "r");
$first = fgets($handle,2048); #get first line.
$outfile="temp";
$o = fopen($outfile,"w");
while (!feof($handle)) {
    $buffer = fgets($handle,2048);
    fwrite($o,$buffer);
}
fclose($handle);
fclose($o);
rename($outfile,$file);
4 голосов
/ 09 марта 2010

Я бы обычно не рекомендовал открывать оболочку для такого рода вещей, но если вы делаете это нечасто для действительно больших файлов, вероятно, есть что сказать:

$lines = `wc -l myfile` - 1;
`tail -n $lines myfile > newfile`;

Это просто и не требует считывания всего файла в память.

Я бы не рекомендовал это для небольших файлов или для очень частого использования. Слишком высокие накладные расходы.

2 голосов
/ 09 марта 2010

Вы можете хранить позиционную информацию в самом файле. Например, первые 8 байтов файла могут хранить целое число. Это целое число является байтовым смещением первой реальной строки в файле.

Итак, вы больше никогда не удаляете строки. Вместо этого удаление строки означает изменение начальной позиции. fseek () и затем читать строки как обычно.

В конечном итоге файл станет большим. Вы можете периодически очищать потерянные строки, чтобы уменьшить размер файла.

А если серьезно, просто используйте базу данных и не делайте ничего подобного.

2 голосов
/ 09 марта 2010

Вот один из способов:

$contents = file($file, FILE_IGNORE_NEW_LINES);
$first_line = array_shift($contents);
file_put_contents($file, implode("\r\n", $contents));

Существует бесчисленное множество других способов сделать это, но все методы должны были бы каким-то образом отделить первую строку и сохранить остальные. Вы не можете избежать переписывания всего файла. Альтернативный дубль:

list($first_line, $contents) = explode("\r\n", file_get_contents($file), 2);
file_put_contents($file, implode("\r\n", $contents));
0 голосов
/ 30 января 2016

Я думаю, что это лучше для любого размера файла

$myfile = fopen("yourfile.txt", "r") or die("Unable to open file!");
$ch=1;

while(!feof($myfile)) {
  $dataline= fgets($myfile) . "<br>";
  if($ch == 2){
  echo str_replace(' ', '&nbsp;', $dataline)."\n";
  }
  $ch = 2;
} 
fclose($myfile);
0 голосов
/ 09 марта 2010

Вы можете использовать метод file ().

Получает первую строку

$content = file('myfile.txt');
echo $content[0];  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...