Ответ 1
Нет более эффективного способа сделать это, кроме как переписать файл.
У меня есть 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
Очевидно, что это работает, но мне было интересно, есть ли более умный (или более эффективный) способ сделать это?
В моем простом решении я в основном читаю и переписываю весь файл только для того, чтобы взять и удалить первую строку.
Нет более эффективного способа сделать это, кроме как переписать файл.
Вчера я придумал эту идею:
function read_and_delete_first_line($filename) {
$file = file($filename);
$output = $file[0];
unset($file[0]);
file_put_contents($filename, $file);
return $output;
}
Нет необходимости создавать второй временный файл и не помещать весь файл в память:
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);
}
Это сдвинет первую строку файла, вам не нужно будет загружать весь файл в память, как вы, используя функцию "файл". Может быть, для небольших файлов немного медленнее, чем с "файлом" (может быть, но я уверен, что нет), но он может управлять самыми большими файлами без проблем.
$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);
}
Обычно я не рекомендую открывать оболочку для такого рода вещей, но если вы делаете это нечасто по действительно большим файлам, возможно, что-то нужно сказать для:
$lines = `wc -l myfile` - 1;
`tail -n $lines myfile > newfile`;
Это просто, и это не связано с чтением всего файла в памяти.
Я бы не рекомендовал это для небольших файлов, или очень частое использование. Слишком высокие накладные расходы.
вы можете перебирать файл, а не помещать их в память
$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);
Здесь один из способов:
$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 байтов файла могут хранить целое число. Это целое число является смещением байта первой реальной строки в файле.
Итак, вы никогда не удаляете строки. Вместо этого удаление строки означает изменение начальной позиции. fseek(), а затем читать строки как обычно.
В конечном итоге файл станет большим. Вы можете периодически очищать оси сирот, чтобы уменьшить размер файла.
Но серьезно, просто используйте базу данных и не делайте таких вещей.
Я думаю, что это лучше всего для любого размера файла
$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(' ', ' ', $dataline)."\n";
}
$ch = 2;
}
fclose($myfile);
Моя проблема была в больших файлах. Мне просто нужно было отредактировать или удалить первую строку. Это было решение, которое я использовал. Не требуется загружать полный файл в переменную. В настоящее время эхо, но вы всегда можете сохранить содержимое.
$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);
Вы можете использовать метод file().
Получает первую строку
$content = file('myfile.txt');
echo $content[0];