遗留PHP系统将一个巨大的日志文件(~5gb)直接读取到内存中的变量并进行一些处理。
编辑:关于阅读5gb到内存是非常不推荐和其他建议请相信,由于我们无法改变的一些传统设计,这必须保持不变。
现在我需要通过另一项服务处理数据,每次调用最多需要1000行。
我尝试过两种方法,两种方法都有效。
1-将新行char中的整个字符串拆分为一个数组,然后使用array_chunk将该数组拆分为子数组,然后取出每个子数组并使用implode生成一个字符串
$logFileStr; // a variable that already contains 5gb file as string
$logLines = explode(PHP_EOL, $logFileStr);
$lineGroups = array_chunk($logLines, 1000);
foreach($lineGroups as $lineGroup)
{
$linesChunk = implode(PHP_EOL, $lineGroup);
$archiveService->store($linesChunk);
}
优点:它很快,因为一切都在记忆中起作用 缺点:涉及大量过度工作和需要大量的记忆
2-最初将字符串变量的内容写入本地临时文件。然后使用exec函数拆分文件
split -l 1000 localfile
每个产生1000行的大量文件。 然后我可以简单地递归读取文件并将每个文件作为单个字符串处理。
优点:维护更简单,更容易
缺点:磁盘I / O涉及速度慢,写入读取开销很多
我的问题是,因为我已经在内存中有一个包含整个字符串的变量,我怎样才能以可迭代的方式从该变量中读取每行1000行的块,以便我可以避免写入磁盘或生成新数组重新合并开销?
答案 0 :(得分:0)
解决此问题的一种方法是使用以下步骤:
我创建了一个示例php代码,遵循以上步骤:
<?php
$str = "line1\nline2\nline3\nline4\nline5\n"; // Sample string
$max_new_lines = 2; // Max number of lines. Replace this with 1000
$str_length = strlen($str);
$new_line_count = 0;
$str_chunk = "";
$start = 0;
// Loop through every character of the string
for ($i = 0; $i < $str_length; ++$i) {
if ($str[$i] == "\n") {
++$new_line_count;
// If we reached the max number of newlines, extract the substring
if (($new_line_count % $max_new_lines) == 0) {
$str_chunk = substr($str, $start, $i - $start);
$start = $i + 1;
// echo "\n\nchunk:\n" . $str_chunk;
}
}
}
// Extract the remaining lines
$str_chunk = substr($str, $start, $i - $start);
// echo "\n\nchunk:\n" . $str_chunk;
答案 1 :(得分:0)
在进行了一些更多的研究后,我偶然发现了这个问题php explode every third instance of character,在对那里发布的答案进行了一些修改后(https://stackoverflow.com/a/1275110/7260022),我想出了这个片段,暂时比以前的方法效果更好
$logFileStr; // a variable that already contains 5gb file as string
$chunks = preg_split('/((?:[^\n]*\n){1000})/', $logFileStr, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
print_r($chunks);
在测试字符串上,结果如下所示(拆分为3)
Array
(
[0] => 13923
27846
311769
[1] => 831384
935307
1039230
[2] => 1558845
1662768
1766691
[3] => 1870614
)
正则表达式的说明如下
?:匹配而不创建捕获组
[^ \ n]与任何非新行
匹配*量词 - 在零和无限时间之间匹配,尽可能多次,根据需要回馈(贪婪)
{1000}量词 - 准确匹配1000次
标志PREG_SPLIT_DELIM_CAPTURE也会在结果集中添加新行字符。