Read a file backwards line by line using fseek

后端 未结 9 1963
温柔的废话
温柔的废话 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:20
    <?php
    
    class ReverseFile implements Iterator
    {
        const BUFFER_SIZE = 4096;
        const SEPARATOR = "\n";
    
        public function __construct($filename)
        {
            $this->_fh = fopen($filename, 'r');
            $this->_filesize = filesize($filename);
            $this->_pos = -1;
            $this->_buffer = null;
            $this->_key = -1;
            $this->_value = null;
        }
    
        public function _read($size)
        {
            $this->_pos -= $size;
            fseek($this->_fh, $this->_pos);
            return fread($this->_fh, $size);
        }
    
        public function _readline()
        {
            $buffer =& $this->_buffer;
            while (true) {
                if ($this->_pos == 0) {
                    return array_pop($buffer);
                }
                if (count($buffer) > 1) {
                    return array_pop($buffer);
                }
                $buffer = explode(self::SEPARATOR, $this->_read(self::BUFFER_SIZE) . $buffer[0]);
            }
        }
    
        public function next()
        {
            ++$this->_key;
            $this->_value = $this->_readline();
        }
    
        public function rewind()
        {
            if ($this->_filesize > 0) {
                $this->_pos = $this->_filesize;
                $this->_value = null;
                $this->_key = -1;
                $this->_buffer = explode(self::SEPARATOR, $this->_read($this->_filesize % self::BUFFER_SIZE ?: self::BUFFER_SIZE));
                $this->next();
            }
        }
    
        public function key() { return $this->_key; }
        public function current() { return $this->_value; }
        public function valid() { return ! is_null($this->_value); }
    }
    
    $f = new ReverseFile(__FILE__);
    foreach ($f as $line) echo $line, "\n";
    
    0 讨论(0)
  • 2020-11-27 08:21

    If you are going to read the entire file in anyways, just use file() to read the file in as an array (each line is each element in the array) and then use array_reverse() to flip the array backwards and loop through that. Or just do a reverse for loop where you start at the end and decrement on each loop.

    $file = file("test.txt");
    $file = array_reverse($file);
    foreach($file as $f){
        echo $f."<br />";
    }
    
    0 讨论(0)
  • 2020-11-27 08:24

    To completely reverse a file:

    $fl = fopen("\some_file.txt", "r");
    for($x_pos = 0, $output = ''; fseek($fl, $x_pos, SEEK_END) !== -1; $x_pos--) {
        $output .= fgetc($fl);
        }
    fclose($fl);
    print_r($output);
    
    

    Of course, you wanted line-by-line reversal...

    
    $fl = fopen("\some_file.txt", "r");
    for($x_pos = 0, $ln = 0, $output = array(); fseek($fl, $x_pos, SEEK_END) !== -1; $x_pos--) {
        $char = fgetc($fl);
        if ($char === "\n") {
            // analyse completed line $output[$ln] if need be
            $ln++;
            continue;
            }
        $output[$ln] = $char . ((array_key_exists($ln, $output)) ? $output[$ln] : '');
        }
    fclose($fl);
    print_r($output);
    
    

    Really though, Jonathan Kuhn has the best answer IMHO above. The only cases you'd not use his answer that I know of is if file or like functions are disabled via php.ini, yet the admin forgot about fseek, or when opening a huge file just get the last few lines of contents would magically save memory this way.

    Note: Error handling not included. And, PHP_EOL didn't cooperate, so I used "\n" to denote end of line instead. So, above may not work in all cases.

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