我有一个脚本,每次调用时都会获取文件的第一行。已知每条线的长度完全相同(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
显然它有效,但我想知道是否有更智能(或更有效)的方法来做到这一点?
在我的简单解决方案中,我基本上读取并重写整个文件,只是为了删除第一行。
答案 0 :(得分:20)
昨天我提出了这个想法:
function read_and_delete_first_line($filename) {
$file = file($filename);
$output = $file[0];
unset($file[0]);
file_put_contents($filename, $file);
return $output;
}
答案 1 :(得分:14)
除了重写文件之外,没有其他方法可以做到这一点。
答案 2 :(得分:12)
无需创建第二个临时文件,也无需将整个文件放在内存中:
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);
}
答案 3 :(得分:6)
这将移动文件的第一行,您不需要像使用“文件”功能一样将整个文件加载到内存中。也许小文件比'文件'慢一点(也许我打赌不是)但是能够毫无问题地管理最大的文件。
$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 :(得分:4)
我通常不建议为这种事情打开一个shell,但是如果你不经常在非常大的文件上这样做,那么可能会有一些说法:
$lines = `wc -l myfile` - 1;
`tail -n $lines myfile > newfile`;
这很简单,并且不涉及将整个文件读入内存。
我不建议将此用于小文件,或者非常频繁使用。开销太高了。
答案 5 :(得分:4)
你可以迭代文件,而不是将它们全部放在内存中
$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);
答案 6 :(得分:2)
这是一种方式:
$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));
答案 7 :(得分:2)
您可以将位置信息存储到文件本身中。例如,文件的前8个字节可以存储整数。此整数是文件中第一个实线的字节偏移量。
所以,你再也不会删除行了。相反,删除一行意味着改变起始位置。 fseek()到它然后正常读取行。
该文件最终会变大。您可以定期清理孤立的行以减小文件大小。
但严重的是,只需使用数据库,不要做这样的事情。
答案 8 :(得分:0)
我认为这适用于任何文件大小
$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);
答案 9 :(得分:0)
我的问题是大文件。我只需要编辑或删除第一行。这是我使用的解决方案。不需要将完整文件加载到变量中。当前回显,但是您始终可以保存内容。
$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);
答案 10 :(得分:0)
这里的解决方案对我而言效果不佳。 我的解决方案从文件中获取最后一行(不是第一行,对于我来说,获取第一行或最后一行并不重要),然后从该文件中删除该行。 即使文件很大(> 150000000行),这也非常快。
function file_pop($file)
{
if ($fp = @fopen($file, "c+")) {
if (!flock($fp, LOCK_EX)) {
fclose($fp);
}
$pos = -1;
$found = 0;
while ($found < 2) {
if (fseek($fp, $pos--, SEEK_END) < 0) { // can not seek to position
rewind($fp); // rewind to the beginnung of the file
break;
};
if (ord(fgetc($fp)) == 10) { // newline
$found++;
}
}
$lastpos = ftell($fp); // get current position of file
$lastline = fgets($fp); // get current line
ftruncate($fp, $lastpos); // truncate file to last position
flock($fp, LOCK_UN); // unlock
fclose($fp); // close the file
return trim($lastline);
}
}
答案 11 :(得分:-2)
您可以使用file()方法。
获取第一行
$content = file('myfile.txt');
echo $content[0];