如果你要讀取的文件是“簡單”的文件,只是以換行符作為分隔符,那么從后往前讀取就會相當(dāng)簡單。然而,CSV是一種更復(fù)雜的格式,有字段和行的分隔符、引號(引號)和轉(zhuǎn)義字符。你可能會遇到數(shù)據(jù),例如
id,name,value 1,foo,"hello world" 2,bar,"hello world" 3, baz,"""hello world"""
這是一個完全有效的CSV,但是大多數(shù)當(dāng)前在論壇上提出的解決方案都會在反向讀取數(shù)據(jù)時出現(xiàn)問題。
最可靠的方法是首先從文件開頭讀取數(shù)據(jù),然后使用這些信息來反向讀取數(shù)據(jù)。最簡單的版本是直接將所有內(nèi)容放入一個數(shù)組中,然后反向讀取該數(shù)組,例如:
$f = fopen("./data/data-esp8266-$idluf-$currentdata.csv", "r"); fgets($f); $lines = []; while (($lines[] = fgetcsv($f)) !== false) {} for( $i=count($lines)-1; $i>=0; --$i ) { $line = lines[$i]; $row = $line[0]; // Dobbiamo ottenere la riga effettiva (è il primo elemento in un array di 1 elemento) $cells = explode(";",$row); echo "<tr>\n"; foreach ($cells as $cell) { echo "<td><a style='text-decoration:none;color:#fff;' class='tooltip' data-tool=' $cell'>" . htmlspecialchars($cell) . "</a></td>\n"; } echo "</tr>\n"; } fclose($f);
但是如果你正在處理一個大文件,你可能遇到內(nèi)存限制,因?yàn)橐鎯λ袛?shù)據(jù)。
一個替代方法是先一次讀取文件,然后只存儲記錄的開始處的文件偏移量,然后使用這些偏移量再次逆向迭代。
function csv_reverse($handle, ...$csv_options) { $offsets = []; do { $offsets[] = ftell($handle); } while($row = fgetcsv($handle, ...$csv_options)); array_pop($offsets); // last offset is EOF for( $i=count($offsets)-1; $i>=0; --$i ) { fseek($handle, $offsets[$i]); yield fgetcsv($handle, ...$csv_options); } } $f = fopen("./data/data-esp8266-$idluf-$currentdata.csv", "r"); fgets($f); // assuming that this discards the header row $lines = []; while (($lines[] = fgetcsv($f)) !== false) {} foreach( csv_reverse($f) as $line ) { // same as above } fclose($f);
有這樣一個權(quán)衡,那就是文件必須被遍歷兩次,但是如果存在內(nèi)存限制,那就不得不這么做。
所有這些說法,更好的選擇是把數(shù)據(jù)放在數(shù)據(jù)庫中,如果可能的話,數(shù)據(jù)庫可以很容易地重新排序數(shù)據(jù)。這個代碼已經(jīng)某種程度上在重新實(shí)現(xiàn)數(shù)據(jù)庫相關(guān)功能,但是更糟糕。
或者,也可以使用for循環(huán)
<?php $lines = file("./data/data-esp8266-$idluf-$currentdata.csv", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); // 將循環(huán)倒序遍歷lines數(shù)組 for ($i = count($lines)-1; $i >= 0; $i--) { $row = $lines[$i]; $cells = explode(";", $row); echo "<tr>\n"; foreach ($cells as $cell) { echo "<td><a style='text-decoration:none;color:#fff;' class='tooltip' data-tool=' $cell'>" . htmlspecialchars($cell) . "</a></td>\n"; } echo "</tr>\n"; } ?>
此方法應(yīng)該比基于函數(shù)array_reverse()的其它方法更快