Read a file backwards line by line using fseek

后端 未结 9 1962
温柔的废话
温柔的废话 2020-11-27 07:33

How do I read a file backwards line by line using fseek?

code can be helpful. must be cross platform and pure php.

many thanks in advance

regards

相关标签:
9条回答
  • 2020-11-27 08:03

    This code read file backwards. This code ignore modifications on reading, example apache access.log new lines on procressing.

    $f = fopen('FILE', 'r');
    
    fseek($f, 0, SEEK_END);
    
    $pos = ftell($f);
    $pos--;
    
    while ($pos > 0) {
        $chr = fgetc($f);
        $pos --;
    
        fseek($f, $pos);
    
        if ($chr == PHP_EOL) {
            YOUR_OWN_FUNCTION($rivi);
            $rivi = NULL;
            continue;
        }
    
        $rivi = $chr.$rivi;
    }
    
    fclose($f);
    
    0 讨论(0)
  • 2020-11-27 08:07

    I know this has been answered already but I found another, maybe faster, way.

    // Read last 5000 chars of 'foo.log' 
    
    if(file_exists('foo.log') && $file = fopen('foo.log', 'r')) {
        fseek($file, -5000, SEEK_END);
    
        $text = stream_get_line($file, 5000); 
    
        var_dump($text);
    
        fclose($file);
    }
    
    0 讨论(0)
  • 2020-11-27 08:11

    Reading the entire file into an array and reversing is fine unless the file is enormous.

    You could perform a buffered read of your file from back to front with something like this:

    • establish a buffer_size B - this should be longer than the longest anticipated line otherwise you'll need some logic for growing the buffer size when lines are too long
    • set offset = file length - buffer_size
    • while the offset>=0
      • read buffer_size bytes from offset
      • read a line - it will be incomplete as we'll have jumped into the middle of a line, so we want to ensure the next buffer we read ends with it. Set offset = offset - buffer_size + line length
      • discard that line, read all following lines into an array and reverse them
      • process this array to do whatever you wanted to do
    0 讨论(0)
  • 2020-11-27 08:13

    The question is asking using fseek, so can only assume that performance is an issue and file() is not the solution. Here is a simple approach using fseek:

    My file.txt

    #file.txt
    Line 1
    Line 2
    Line 3
    Line 4
    Line 5
    

    And the code:

    <?php
    
    $fp = fopen('file.txt', 'r');
    
    $pos = -2; // Skip final new line character (Set to -1 if not present)
    
    $lines = array();
    $currentLine = '';
    
    while (-1 !== fseek($fp, $pos, SEEK_END)) {
        $char = fgetc($fp);
        if (PHP_EOL == $char) {
                $lines[] = $currentLine;
                $currentLine = '';
        } else {
                $currentLine = $char . $currentLine;
        }
        $pos--;
    }
    
    $lines[] = $currentLine; // Grab final line
    
    var_dump($lines);
    

    Output:

    array(5) {
       [0]=>
       string(6) "Line 5"
       [1]=>
       string(6) "Line 4"
       [2]=>
       string(6) "Line 3"
       [3]=>
       string(6) "Line 2"
       [4]=>
       string(6) "Line 1"
    }
    

    You don't have to append to the $lines array like I am, you can print the output straight away if that is the purpose of your script. Also it is easy to introduce a counter if you want to limit the number of lines.

    $linesToShow = 3;
    $counter = 0;
    while ($counter <= $linesToShow && -1 !== fseek($fp, $pos, SEEK_END)) {
       // Rest of code from example. After $lines[] = $currentLine; add:
       $counter++;
    }
    
    0 讨论(0)
  • 2020-11-27 08:17

    Here's a drop in replacement(ish) for fgets($fp) called fgetsr() that reads lines from a file in reverse order.

    This code is verbatim so you should (famous last words) be able to copy it into a file on your server and run it. Though you may well need to change the filename in the fopn() call.

    <?php
        header('Content-Type: text/plain');
        $fp = fopen('post.html', 'r');
        
        while($line = fgetsr($fp)) {
            echo $line;
        }
    
    
    
    
    
    
    
        // Read a line from the file but starting from the end
        //
        // @param $fp integer The file pointer
        //
        function fgetsr($fp)
        {
            // Make this variable persistent inside this function
            static $seeked;
            
            // The line buffer that will eventually be returned
            $line = '';
    
            // Initially seek to the end of the file
            if (!$seeked) {
                fseek($fp, -1, SEEK_END);
                $seeked = true;
            }
            
            // Loop through all of the characters in the file
            while(strlen($char = fgetc($fp)) {
    
                // fgetc() advances that pointer so go back TWO places
                // instead of one
                fseek($fp, -2, SEEK_CUR);
    
                //
                // Check for a newline (LF). If a newline is found
                // then break out of the function and return the
                // line that's stored in the buffer.
                //
                // NB The first line in the file (ie the last to
                //    be read)has a special case
                //
                if (ftell($fp) <= 0) {
                    fseek($fp, 0, SEEK_SET);
                    $line = fgets($fp);
                    fseek($fp, 0, SEEK_SET);
                    return $line;
                } else if ($char === "\n") {
                    $line = strrev($line);
                    return $line . "\n";
                } else {
                    $line .= $char;
                }
            }
        }
    ?>
    
    0 讨论(0)
  • 2020-11-27 08:19

    You cannot fseek line by line, because you do not know how long the lines are until you read them.

    You should either read the whole file into a list of lines, or if the file is too big for that and you only need the last lines, read fixed-sized chunks from the end of the file and implement a bit more complicated logic which detects lines from such data.

    0 讨论(0)
提交回复
热议问题