从文件中删除前X行 PHP

7
我想知道是否有人知道如何用PHP实现这个功能。我正在运行一个涉及打开文件、获取前1000行并对这些行进行一些操作的脚本,然后php文件会打开自身的另一个实例来获取接下来的1000行,以此类推直到读取完整个文件。我使用splfileobject可以定位到某一行,这使得我可以将文件分成1000行的块。但是,我遇到的最大问题是性能问题。我正在处理包含超过1000万行的文件,虽然它可以快速处理前10000行左右,但在那之后会出现巨大的指数级放缓,我认为这是因为需要定位到该点。

我想做的是读取前一千行,然后从文件中删除它们,以便我的脚本总是读取前一千行。是否有一种方法可以在不将其余部分读入内存的情况下实现这一点。其他解决方案包括将每一行读入数组中,然后去掉前X个条目,但对于一千万行,这将消耗太多内存和时间。

如果有任何解决方案或其他建议可以提高性能,将不胜感激。


你认为寻找时间是花费的时间吗? - salathe
我注释掉了迭代行计数器的那一行,这样它总是运行前1000行,速度呈指数级增长。此外,随着时间的推移,它会以指数级减慢,唯一变化的是它正在寻找的行。 - Eric Strom
1
还有一点可能会引起兴趣的是,当使用SplFileObjectseek()方法时,文件仍然被读取直到你寻找的位置(每行都被读取然后丢弃)。这与使用fseek()定位到字节偏移量的方式是不同的。 - salathe
我使用splfileobject的原因是因为它可以按行而不是字节进行查找。但我想这也是导致减速的原因,因为它必须查找到第1000000行或其他行,并读取该行之前的所有内容。 - Eric Strom
1
@Eric 不要逐行查找。每次打开文件时都必须计算行数。将 tell() 或其他返回的字节偏移量存储在 spfileobject 中。这是一个简单的字节计数,可以快速跳过,因为 PHP 不必扫描/计算行结尾。一旦你定位到正确的位置,然后你就可以开始计算行数了。 - Marc B
显示剩余7条评论
2个回答

1

很遗憾,这个问题没有真正的解决方案,因为文件在读取之前总是完全加载到主内存中。

尽管如此,我发布了这个答案,因为这是一个可能的解决方案,但我怀疑它几乎不会改善性能。如果我错了,请纠正我。

您可以使用XML将文件分成1000行的单元,并使用PHP的DomDocument类检索和追加数据。当您想要添加数据时,可以追加子节点,并检索第一个子节点以获取前一千行,并在需要时删除该节点。就像这样:

<document>
    <part>
        . . . 
        Thousand lines here
        . . . 
    </part>
    <part>
        . . . 
        Thousand lines here
        . . . 
    </part>
    <part>
        . . . 
        Thousand lines here
        . . . 
    </part>
    .
    .
    .
</document>

另一种方法:

如果您确信要将部分分成恰好1000行,为什么不将其保存在数据库中,每1000行存储在不同的行中?通过这样做,您肯定会减少文件读写开销并提高性能。


1

在我看来,目标是解析大量数据并将其插入数据库?如果是这样,我不明白为什么要精确地处理1000行有多重要?

我认为我会通过一次读取1 MB的大块数据进入内存,然后从内存块末尾向后扫描找到最后一行的结束符。一旦找到,我就可以保存文件位置和额外的数据(从上一个行结束符到块结尾的部分)。或者,只需使用fseek()将文件指针重置到找到最后一行的位置,可以轻松完成,使用strlen($chunk)即可。

这样,我所要做的就是运行explode("\r\n",$chunk)来分裂块,然后我就拥有了所有需要的行,在适当大小的块中进行进一步处理。

不建议从文件开头删除行。那会导致大量的数据在磁盘上前后移动。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接