簡體   English   中英

這是獲取和刪除文件第一行的最有效方法嗎?

[英]Is this the most efficient way to get and remove first line in file?

我有一個腳本,每次調用它都會獲取文件的第一行。 已知每一行的長度完全相同(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

顯然它有效,但我想知道是否有更聰明(或更有效)的方法來做到這一點?

在我的簡單解決方案中,我基本上讀取和重寫整個文件只是為了取出和刪除第一行

我昨天想出了這個主意:

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

您可以迭代文件,而不是將它們全部放在內存中

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

我通常不建議為這種事情打開一個 shell,但如果你很少在非常大的文件上這樣做,那么可能有一些事情要說:

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

這很簡單,它不涉及將整個文件讀入內存。

我不會推薦這個用於小文件,或者非常頻繁地使用。 開銷太高了

這是一種方法:

$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() 到它,然后正常讀取行。

文件最終會變大。 您可以定期清理孤立的行以減小文件大小。

但說真的,只要使用數據庫,不要做這樣的事情。

您可以使用 file() 方法。

獲取第一行

$content = file('myfile.txt');
echo $content[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(' ', '&nbsp;', $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);

這里的解決方案對我不起作用。 我的解決方案從文件中獲取最后一行(不是第一行,在我的情況下與獲取第一行或最后一行無關)並將其從該文件中刪除。 即使對於非常大的文件(> 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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM