这是获取和删除文件中第一行的最有效方法吗?
我有一个脚本,每次被调用时,都会获取文件的第一行。已知每行的长度完全相同(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
显然它的工作原理,但我不知道是否有更聪明(或更有效)的方式来做到这一点?
在我简单的解决方案中,我基本上是读取并重写整个文件,只是取出并删除第一行。
除了重写文件之外,没有更有效的方法来做到这一点。
这里有一种方法:
$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));
你的第一个例子会产生冗余换行符。如果没有file()的'FILE_IGNORE_NEW_LINES'标志,你不需要再用'implode()'来换行。 – 2010-03-08 21:11:54
@fireeyedboy,不错,固定。 – 2010-03-08 22:34:15
Ulman:+1非常有趣的代码,谢谢!我以前从未使用过文件功能。 – 2010-03-09 18:31:15
您可以使用file()方法。
获取第一线
$content = file('myfile.txt');
echo $content[0];
这对我很好。我不知道为什么有人让你失望。谢谢。我试图给你投票,但你仍然在0. :) – bozdoz 2011-05-28 21:58:08
这种方法对大文件的效率非常低。 – 2013-09-16 06:16:22
这不会删除第一行,它只是获取它。 – 2014-01-24 15:04:00
你可以存储位置信息到文件本身。例如,文件的前8个字节可以存储一个整数。该整数是文件中第一个实际行的字节偏移量。
因此,你永远不会删除行。相反,删除一条线意味着改变开始位置。 fseek(),然后像正常一样读取行。
该文件最终会变大。您可以定期清理孤行,以减小文件大小。
但严重的是,只是使用数据库,不要做这样的事情。
我通常不会建议开放对这种事情的壳,但如果你在真正的大文件很少这样做,有可能什么可说的:
$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);
+1:我认为这样更有效率,但不是更快。如果文件太大而不能适应内存,证明它不会炸毁。 – 2011-05-18 14:45:32
我有这样的想法昨天来了:
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);
}
您能否在代码旁边添加一些简短的注释以解释您在做什么? – 2014-01-24 15:08:28
有趣的想法+1 – 2014-04-25 14:03:12
这段代码不起作用,它只是简单地覆盖了一些行。在[Marcos Fernandez Ramo的回答]中查看基于这个工作版本(https://stackoverflow.com/questions/2404707/is-this-the-most-efficent-way-to-get-and-remove-first -line-in-file/23269245#23269245) – user 2014-12-01 06:07:15
这将移动文件的第一行,你不需要加载像你一样在内存中的整个文件使用'文件'功能。也许小文件比'文件'慢一点(可能但我打赌不是),但能够管理最大的文件没有问题。
$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);
}
我觉得这是最好的任何文件的大小
$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);
你可以让这个更高效的内存(做一个循环,一次读取一行,给他们写了一个在时间除了第一个),但它看起来很复杂,并且容易出错。我会和你一样。没有解决从第一个字节开始按顺序存储文件这一事实。 – 2010-03-08 21:25:14
如果你可以将文件存储为索引,并通过索引执行所有的R/W,也许这个操作会更快,因为你可以简单地从索引中删除该行,这样做比在完整的文件。 但是,如果文件很小,那么I/O的成本将低于维护索引的开销。 – anijhaw 2010-03-08 21:26:21
对于我能想到的类似问题,唯一的高度优化解决方案将涉及文件系统驱动程序中的IOCTL,该文件系统驱动程序会从文件中剪切第一个逻辑块(取决于硬件和实现的大小),而不会触及其余部分。但这是解决不存在问题的学术练习,绝对不是你想要的。 :) – 2010-03-08 21:28:33