Reverse PHP reading of CSV file
P粉512729862
P粉512729862 2023-08-08 18:24:19
0
2
652
<p>I have a PHP script that reads a CSV file, and I want it to read it starting from the last line, that is, in reverse order. </p> <pre class="brush:php;toolbar:false;"><?php $f = fopen("./data/data-esp8266-$idluf-$currentdata.csv", "r"); fgets($f); while (($line = fgetcsv($f)) !== false) { $row = $line[0]; $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); ?></pre> <p><br /></p>
P粉512729862
P粉512729862

reply all(2)
P粉118698740

If the file you want to read is a "simple" file with just newlines as delimiters, reading from back to front will be quite simple. However, CSV is a more complex format, with field and row delimiters, quotation marks (quotes), and escape characters. You may encounter data such as

id,name,value
1,foo,"hello world"
2,bar,"hello 
world"
3, baz,"""hello 
world"""

This is a perfectly valid CSV, but most of the solutions currently proposed on forums will have problems reading the data in reverse.

The most reliable method is to first read the data from the beginning of the file, and then use this information to read the data in reverse direction. The simplest version is to just put everything into an array and then read the array in reverse, for example:

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

But if you are processing a large file, you may run into memory constraints as all the data needs to be stored.

An alternative is to read the file once, then store only the file offsets at the beginning of the record, and then iterate backwards again using those offsets.


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

There is a trade-off that the file must be traversed twice, but if there are memory constraints, then this has to be done.

With all this said, a better option is to put the data in a database where the database can easily reorder the data if possible. This code already reimplements database-related functionality to some extent, but it's even worse.

P粉513316221

Alternatively, you can also use a for loop

<?php
$lines = file("./data/data-esp8266-$idluf-$currentdata.csv", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

// 将循环倒序遍历lines数组
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";
}

?>

This method should be faster than other methods based on the function array_reverse()

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template