最近在工作中遇到了需要读取系统日志的问题,日志文件很大,大概在1G以上甚至更大,随即研究了读取得方法,直接使用PHP自带的函数就可以解决这几个问题,但是绝对不能使用file和file_get_contents,这两个函数是一次性将文件全部加载进来,如果文件在几十M 还是可以的,但是稍大的文件时不能用的,内存是会溢出的 ,贴个自己的方法,欢迎大家指教!如果需要读取大文件的话,可以使用seek定位;这样不需要将文件全部载入内存,效率应该会很高。
<?php
/**
* @param $csvfile CSV文件地址
* @param int $offset 文件起始行数
* @param int $len 读取得行数
* @param mixed $csvFile
*
* @return array 返回结果
*/
public function readBigFile($csvFile, $page = 1, $len = 10000)
{
$splFileObject = new \SplFileObject($csvFile, 'rb');
$splFileObject->setFlags(\SplFileObject::READ_CSV); //非CSV文件注释掉
if ($page > 0 && $len > 0) {
$offset = 1 + ($page - 1) * $len;
$splFileObject->seek($offset);
}
$content = [];
while ((!($splFileObject->eof()) && $len)) {
$row = $splFileObject->current();
if (isset($row[0])) {
$content[] = $row;
}
$splFileObject->next();
--$len;
}
return $content;
}
/**
* 文件读取
*
* @param String $filename 文件地址
* @param Int $count 读取得行数
* @return String 返回结果
*/
function readBigFile($filename, $num = 10000)
{
$content = [];
$log = new \SplFileObject($filename);
foreach ($log as $key => $data) {
if ($key + 1 >= $num) {
break;
}
//去除换行符
$content[] = str_replace(["\r\n", "\n"], '', $data);
$reg = "/INSERT INTO user.*?errorMessage:An exception occurred/i";
if (preg_match($reg, $content, $arr)) {
$sql = str_replace("errorMessage:An exception occurred", ";", $arr['0']);
file_put_contents("/mnt/d/cdr.sql", $sql.PHP_EOL, FILE_APPEND);
}
}
return $content;
}
$filename = 'E:/2010log.log';//需要读取的文件
$count = 20;//读取行数
$data = readBigFile($filename, $count);