Это самый эффективный способ получить и удалить первую строку в файле?

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

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

$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

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

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

Ответы

Ответ 1

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

Ответ 2

Вчера я придумал эту идею:

function read_and_delete_first_line($filename) {
  $file = file($filename);
  $output = $file[0];
  unset($file[0]);
  file_put_contents($filename, $file);
  return $output;
}

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

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

Это просто, и это не связано с чтением всего файла в памяти.

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

Ответ 6

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

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

Ответ 7

Здесь один из способов:

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

Ответ 8

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

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

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

Но серьезно, просто используйте базу данных и не делайте таких вещей.

Ответ 9

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

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

Ответ 10

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

$fh = fopen($local_file, 'rb');
echo "add\tfirst\tline\n";  // add your new first line.
fgets($fh); // moves the file pointer to the next line.
echo stream_get_contents($fh); // flushes the remaining file.
fclose($fh);

Ответ 11

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

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

$content = file('myfile.txt');
echo $content[0];