很多时候,要处理文件,一般最先想到的就是file_get_contents() 等函数,但是在文件比较大的情况下,盲目的使用这样的函数会造成PHP的内存溢出(不使用任何参数)等致命错误。
当然,有一些函数能够一行一行的读取数据,比如fread(),fgetcsv(),而事实上,一般操作csv文件也是使用这几个函数,在正常使用过程中,只要没有特殊的需求,还是可以胜任大多数的情况。比如,如果有一个2000w~5000w条数据的文件,只想获取文件的总行数怎么办,循环累加吗?这显然是最直接的方法,其实还有更好的方法。
在PHP5以后,PHP为文件提供了一个面向对象接口类:SplFileObject。
详情可以查看:
The SplFileObject class
http://www.php.net/manual/zh/class.splfileobject.php这里提供一段简单有趣的程序。
function useSplFileObject($csvfile) {
$splFileObject = new SplFileObject($csvfile, 'rb');
$splFileObject->seek(filesize($csvfile));
$num = $splFileObject->key();
return $num;
}
$data = useSplFileObject('test.csv');
var_dump($data);
贴个对比的(循环累加):
$header = fopen('test.csv','r');
$i = 0;
while( !feof($header) )
{
fgetcsv($header);
$i++;
}
var_dump($i);
系统命令行直接获取:
通过上面可以看出,单纯获取文件的行数,这种需求,使用PHP提供的SplFileObject类是比较好的选择。
贴一个拓展的(offset):
function useSplFileObject($csvfile,$offset,$len) {
$splFileObject = new SplFileObject($csvfile, 'rb');
$splFileObject->seek(filesize($csvfile));
$splFileObject->seek($offset);
while ((!($splFileObject->eof()) && $len)){
$content[]=$splFileObject->current();
$splFileObject->next();
$len--;
}
return $content;
}
$data = useSplFileObject('test.csv',12000000,10);
var_dump($data);
以上测试test.csv输出从12000000行起,10行的内容。
这是一个不错的体验,尤其是大文件获取,不方便调程序的执行时间和内存的情况下。
当然,原生的fgetcsv,也是可以的。上面的程序相应修改如下:
function csv_get_offsetlines($csvfile, $lines, $offset = 0) {
if(!$fp = fopen($csvfile, 'r')) {
return false;
}
$offset = $offset - 1;
$i = $j = 0;
while (false !== ($line = fgets($fp))) {
if($i++ < $offset) {
continue;
}
break;
}
$data = array();
while(($j++ < $lines) && !feof($fp)) {
$data[] = fgetcsv($fp);
}
fclose($fp);
return $data;
}
$data = csv_get_offsetlines('test.csv', 10, 12000000);
var_dump($data);
由于数据有点长,只贴以下部分图片: