【问题标题】:reading a block of lines in a file using php使用 php 读取文件中的一行行
【发布时间】:2011-07-18 12:59:02
【问题描述】:

考虑到我有一个 100GB 的 txt 文件,其中包含数百万行文本。我如何使用 PHP 逐行读取此文本文件?

我不能使用file_get_contents();,因为文件太大。 fgets() 还逐行读取文本,这可能需要更长的时间才能完成整个文件的读取。

如果我将使用fread($fp,5030),其中“5030”是它必须读取的某个长度值。会不会出现因为已经达到最大长度而无法读取整行(比如停在行中间)的情况?

【问题讨论】:

  • 到底是什么问题? fread 有限制吗?

标签: php file fgets fread


【解决方案1】:

我不能使用 file_get_contents();因为文件太大。 fgets() 还逐行读取文本,这可能需要更长的时间才能完成整个文件的读取。

不明白,为什么你不能使用fgets()

$blocksize = 50; // in "number of lines"
while (!feof($fh)) {
  $lines = array();
  $count = 0;
  while (!feof($fh) && (++$count <= $blocksize)) {
    $lines[] = fgets($fh);
  }
  doSomethingWithLines($lines);
}

无论如何,读取 100GB 都需要时间。

【讨论】:

  • 如果行很短,这可能比 fread 方法慢(大量单独的小读取比较少的大读取具有更多的 IO 开销)。
【解决方案2】:

fread 方法听起来是一个合理的解决方案。您可以通过检查字符串中的最后一个字符是否为换行符 ('\n') 来检测是否已到达行尾。如果不是,那么您可以读取更多字符并将它们附加到现有字符串中,或​​者您可以将字符串中的字符修剪回最后一个换行符,然后使用fseek 调整您在文件中的位置。

旁白:您是否知道读取一个 100GB 的文件需要非常很长时间?

【讨论】:

    【解决方案3】:

    我认为你必须使用 fread($fp, somesize),并手动检查你是否已经建立了行尾,否则读取另一个块。

    希望这会有所帮助。

    【讨论】:

      【解决方案4】:

      我建议在函数中实现单行的读取,将特定步骤的实现细节隐藏在代码的其余部分中 - 处理函数必须不关心如何检索该行。然后您可以使用fgets() 实现您的第一个版本,然后尝试其他方法如果您发现它太慢了。很可能是最初的实现太慢了,但关键是:在你进行基准测试之前你不会知道。

      【讨论】:

        【解决方案5】:

        我知道这是一个老问题,但我认为对于最终找到这个问题的任何人来说,一个新的答案是有价值的。

        我同意阅读 100GB 需要时间,这就是为什么我也同意我们需要找到最有效的选项来阅读它,这样它就可以尽可能少,而不是仅仅想“谁在乎它有多少如果是已经很多了”,所以,让我们找出我们可能的最短时间。

        另一种解决方案:

        缓存一大块原始数据

        使用 fread 读取该数据的缓存

        逐行阅读

        从缓存中逐行读取,直到缓存结束或找到数据结束

        读取下一个块并重复

        获取块中未处理的最后一部分(您正在寻找行分隔符的部分)并将其移动到前面,然后读取您定义的大小减去未处理数据大小的块并将其放入就在那个未处理的块之后,然后,你去,你有一个新的完整块。
        重复逐行读取,直到文件被完全读取。

        您应该使用大于任何预期行大小的缓存块。

        缓存越大,读取速度越快,但使用的内存越多。

        【讨论】:

        • 我在与@OP 相似的船上,寻找最快的方式来逐行读取 300 个文件,每个 5 GB。我将做很多不同大小的速度测试,但我想知道 fread() 的一个好的起点是什么? 1KB? 1MB? 1GB?我的服务器只有 4 GB 的 RAM,所以可能不是演出。另一方面,将多个插入合并到一个大的 MySQL 插入中,INSERT 查询大小的良好起点是什么?
        • 关于缓存大小要考虑的一件事是,如果您使用的是命令行 PHP 或 web PHP,如果您使用的是 web PHP,则需要考虑可能会重用同一个线程,如果你提高了很多内存的使用,它会拖到下一次重用,你的总体内存使用将保持在高位。
        • 关于你的情况下缓存的大小,我会说1k非常小,1G肯定太大了。由于您要进行测试,因此您可以很好地测试多个数字,我建议您至少尝试 512k,并且可能不超过 1 到 4 MB 或类似的大小。只是想避免阅读太频繁,但你根本不需要避免阅读。我会说,如果您可以阅读 100 到 1000 行,那么您就很好。恕我直言
        猜你喜欢
        • 1970-01-01
        • 2016-11-22
        • 2021-02-01
        • 2016-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多