读取缺少“新行”的文本文件

时间:2014-07-01 17:43:32

标签: php

让日志文件不时缺少“新行”

2010.12.17 04:26    127.0.0.1   user:user1  region:NA   ERROR: Invalid password
2010.12.17 04:27    127.0.0.1   user:user1  region:AP   ERROR: Invalid password
2010.12.17 04:32    127.0.0.12010.12.17 04:32   127.0.0.1   user:user1  region:AP   ERROR: Invalid password
2010.12.17 04:32    127.0.0.1   user:user1  region:NA   ERROR: Invalid password

在上面第三行的例子中:

2010.12.17 04:32 127.0.0.1应该在一行

2010.12.17 04:32 127.0.0.1 user:user1 region:AP ERROR: Invalid password应该在另一行。

我需要将行读入数组,就像file()正在做的那样,但是使用了更正的行。

我无法通过在需要的地方插入新行来触摸文件本身来纠正它。

我在考虑fread,但这会将整个文件内容读入一个字符串。也许我应该解析这个大字符串..?

您是否更了解如何实现这一目标?

3 个答案:

答案 0 :(得分:2)

如果您可以将整个文件加载到内存中,则可以根据行的开头使用preg_split()

$result = preg_split('/(?=\d{4}\.\d{2}\.\d{2})/m', $body);

print_r($result); // ignore first array element

答案 1 :(得分:0)

您必须找到一种方法来检测这些换行符的位置,以便您可以将数据读取到这些位置。这意味着您需要查看文件行格式,并尝试根据该格式进行阅读。最简单的方法是使用正则表达式,它将尝试匹配尽可能多的文本,直到该模式开始下一行。匹配应考虑可能存在行结束标记。

幸运的是,日志的每一行都以一个时间戳开始,该时间戳在整个文件中的变化不大。通常,日志涵盖一天,因此您可以将regexp作为日志的第一个字符,这必须是第一行的开头。

$file = fopen($logname, "r");    
$content = array();
$date = fread($file, 9); // date length
fseek($file, 0);
$pattern = $date.".*?(".$date.")?";
while ($data = fread($file, 4096)){
    $buff .= $data;
    while (preg_match($pattern, $data,$matches = array())){
        $content[] = $matches[0];
        $buff = substr($buff, strlen($matches[0]));
    }
} // end of file
if (strlen($buff)){
    echo ”extra data at end of log : " . $buff;
}

您应该能够根据日志时间戳格式调整该代码。

答案 2 :(得分:0)

根据Jack的回答,编写了一个使用fopen和fgets的代码:fgets逐行读取,我猜它不会像使用file()或fread()那样加载内存。

    $flog_path="/srv/www/****.log";
    $ftemp = fopen($flog_path,"r");
    while ($s=fgets($ftemp)) {
        $elem=preg_split('/(?=\d{4}\.\d{2}\.\d{2})/m', $s);
        foreach (array_filter($elem) as $v) $result[] = trim($v);
    }