使用fseek逐行逐行读取文件
如何使用fseek逐行逐行读取文件?
代码可能会有所帮助。 必须是跨平台和纯粹的PHP。
提前谢谢了
问候
杰拉
问题是使用fseek,所以只能假设性能是一个问题,file()不是解决scheme。 这是一个使用fseek的简单方法:
我的file.txt
#file.txt Line 1 Line 2 Line 3 Line 4 Line 5
和代码:
<?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);
输出:
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" }
您不必像我一样追加到$ lines数组中,如果这是脚本的目的,则可以直接打印输出。 如果要限制行数,也很容易引入计数器。
$linesToShow = 3; $counter = 0; while ($counter <= $linesToShow && -1 !== fseek($fp, $pos, SEEK_END)) { // Rest of code from example. After $lines[] = $currentLine; add: $counter++; }
如果要读取整个文件,只需使用file()以数组的forms读取文件(每行是数组中的每个元素),然后使用array_reverse()向后翻转数组, 。 或者只是做一个反向循环,你从最后开始,每个循环递减。
$file = file("test.txt"); $file = array_reverse($file); foreach($file as $f){ echo $f."<br />"; }
<?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";
要完全反转文件:
$ 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($输出);
当然,你想逐行倒转…
$ fl = fopen(“\ some_file.txt”,“r”); ($ x_pos = 0,$ ln = 0,$ output = array(); fseek($ fl,$ x_pos,SEEK_END)!== -1; $ x_pos--){ $ char = fgetc($ fl); if($ char ===“\ n”){ //分析完成的行$ output [$ ln],如果需要的话 $ LN ++; 继续; } $ output [$ ln] = $ char。 ((array_key_exists($ ln,$ output))?$ output [$ ln]:''); } FCLOSE($ FL); 的print_r($输出);
真的,乔纳森·库恩有上面的恕我直言的最好的答案。 唯一的情况你不会使用他的答案,我知道的是,如果file
或类似的function通过php.ini被禁用,但pipe理员忘了fseek,或者当打开一个巨大的文件只是得到最后几行的内容会神奇这样节省内存。
注意:error handling不包括在内。 而且,PHP_EOL没有合作,所以我用“\ n”来表示行尾。 所以,以上可能不适用于所有情况。
你不能逐行阅读,因为你不知道线条有多长,直到你阅读它们。
您应该将整个文件读入行列表,或者如果文件太大,而且只需要最后一行,则从文件尾部读取固定大小的块,并实现一些更复杂的逻辑来自这些数据的线。
将整个文件读取到一个数组中,反转是正常的,除非文件很大。
你可以用这样的方式从后到前对文件进行缓冲读取:
- build立一个buffer_size B–这应该比最长的预计的行长,否则当行太长的时候你需要一些增长缓冲区大小的逻辑
- 设置偏移量=文件长度 – buffer_size
- 而偏移量> = 0
- 从偏移量读取buffer_size字节
- 读一行 – 这将是不完整的,因为我们会跳到一行的中间,所以我们要确保我们读的下一个缓冲区以它结束。 设置偏移量=偏移量 – 缓冲区大小+行长度
- 丢弃该行,将所有后续行读入数组并将其反转
- 处理这个数组来做任何你想做的事情
此代码向后读取文件。 这段代码忽略修改阅读,例如apache access.log 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);