例如我有一个文件xxxxx.dat(1G大小)这个文件里的数据格式是:111111111111111111111111111111111111111111."\r\n"
222222222222222222222222222222222222222222."\r\n"
......
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."\r\n"
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb."\r\n"
......
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz."\r\n"如果我要从zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz往上读取20条记录,该怎么读取?
222222222222222222222222222222222222222222."\r\n"
......
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."\r\n"
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb."\r\n"
......
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz."\r\n"如果我要从zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz往上读取20条记录,该怎么读取?
<?php
$filename = "c:/logfile.log"; // 需要读取的文件
$sep = "\n"; // 行分隔符
$count = 5; // 读取行数
$handle = fopen($filename,"a+");
$len= strlen($sep);
$pos = -$len;
$i = 0;
$content = ''; // 最终内容
$cContent = '';// 当前读取内容寄存
do{
fseek($handle,$pos,SEEK_END);
$cContent = fread($handle,$len);
$content = $cContent.$content;
$pos -= $len;
if ($sep === $cContent ){
$i++;
}
}while($i<$count);
echo $content;
?>
$a = file("xxx.dat");
$b = count($a);
$c = $b-20;
for($i=$c;$i<$b;$i++)
{
echo $a[$i]."<br/>";
}
$fp = fopen('test.txt','r');
$fs = filesize('test.txt');
$i = $n = NULL;
while($i<4)
{
fseek($fp,$fs--);
$n = fread($fp,1);
($n=="\n")?$i++:1;
echo $n;
}
fclose($fp);
一楼的方法在大文件时小心死掉.一次性全部读入内存甚不划算.
system("tail -n 20 test.txt");
如果不可以:
3楼的fopen吧
$f = file("xxxxx.dat");
$count = count($f);
print_r(array_slice($f,$count-20,$count));
?>
或者,没有现成的函数,就走不动了,实在没必要。(而且到底自己写的效率高还是系统自带的效率高,也要测试才知道)支持1楼3楼的自己写的功能函数。只是1楼的没看懂,len的长度好像就是“\n”,好像意思不太对。
$data = file_get_contents($file_name);
$content = ''; //输出内容
$line_count = 0; //行数计算
$LINE = 20; //需要截取的行数
$i = $data_len = strlen($data);
while ( $i-- > 0 && $line_count < $LINE ) {
$content = $content.$data{$i};
if ( $data{$i} == "\n" )
$line_count++;
}
echo strrev($content);
在E盘放了个120W行的文件测试,效率似乎还不错。
任何用 file或file_get_contents的.你们图代码的方便,就不管内存的死活了?
<?php
function getLatestLines($filename,$count = 20,$sep = "\r\n"){ // 注意这里必须用双引号
$content = ''; // 最终内容
$_current = '';// 当前读取内容寄存
$seper = '';// 分隔符判断
$seperLen = strlen($sep); // 分隔符长度
$step= 1; // 每次走多少字符
$pos = 0;// 起始位置 -1 就是从最后一个开始
$i = 0;
$count--;
$handle = fopen($filename,'a+'); //读写模式,指针会被放在最后 当然也可以探测出 filesize然后从最后往前读。
while($i < $count && fseek($handle,$pos,SEEK_END) ===0){
// SEEK_END - 设定位置为文件尾加上 offset 。(要移动到文件尾之前的位置,需要给 offset 传递一个负值。)
$_current = fread($handle,$step);
$seper = $_current.$seper;
if (strlen($seper)>$seperLen){
$seper = substr($seper, 0, -$seperLen); // 截取当前字符最后几位。与分隔符匹配,所以长度和分隔符要一样。
}
$content = $_current.$content;
$pos -= $step; // 向后退
if ($sep === $seper ){ // 判断是否是换行或其他分隔符
$i++;
}
}
fclose($handle);
return $content;
}
$filename = 'c:/logfile.log'; // 需要读取的文件 3.5G 文件已测试过。
$sep = "\r\n"; // 行分隔符 注意这里必须用双引号-_-#
$count = 20; // 读取行数 \r\n 读取3行以下有点问题
echo getLatestLines($filename,$count,$sep);
?>
function getlines($filename) {
$l = 0;
$fp = fopen($filename, 'r');
while(fgets($fp)) $l++;
fclose($fp);
return $l;
}/*** 定位到指定行 ***/
function poslines($filename, $num) {
$l = 0;
$fp = fopen($filename, 'r');
while(fgets($fp)) {
if($l == $num) break;
$l++;
}
return $fp;
}/*** 应用 ***/
$filename = "xxxxx.dat";
$fp = poslines($filename, getlines($filename) - 20));
$buf = fgets($fp);
...
不过,\n虽为2个字符,但"\n"却是1个字符,请高人明察。
还有,3楼一个个字符输出,是不可行的。误人子弟的方法,切不可提。另,
鉴于1G的文件实在太大,贫僧不能亲自测试(即便复制内容时不死机,保存时也怕会死机),因此也懒得编码了。
有了18楼(贫僧没细看,有点长)和19楼(有点偷懒)的代码,贫僧作为新手就不献丑了。
凡是用fgets的地方均不能和fseek配合.fgets是从指针令开始取整行.
长度未知的话等于白废.你前面提到的多字节问题.我可以直接忽略过.懒得再答此类问题了.