分割巨大文件的最佳方式



我正在尝试拆分一个巨大的文本文件(~5亿行文本),这是非常规则的,看起来像这样:

-- Start ---
blah blah
-- End --
-- Start --
blah blah
-- End --
...

的地方……暗示一个重复的模式和"blah blah"是可变的长度~ 2000行。我想把第一个

分开
-- Start --
blah blah
-- End --

块放到一个单独的文件中,并以最快的(运行时间,考虑到我会运行很多次)可能的方式从原始文件中删除它。

理想的解决方案是从原始文件中剪切初始块并将其粘贴到新文件中,而不加载庞大的初始文件的尾部。

我尝试用以下方式进行csplit:

csplit file.txt /End/+1 

,这是一种有效的方法,但在时间上不是很有效。

编辑:如果我们从文件中删除最后一个"start-end"块而不是第一个,是否有解决方案?

如果您希望从原始文件中删除开头部分,那么您别无选择,只能读取和写入文件的其余部分。要删除结尾(如您在编辑中建议的),它可以更有效:

use File::ReadBackwards;
use File::Slurp 'write_file';
my $fh = File::ReadBackwards->new( 'inputfile', "-- End --n" )
    or die "couldn't read inputfile: $!n";
my $last_chunk = $fh->readline
    or die "file was emptyn";
my $position = $fh->tell;
$fh->close;
truncate( 'inputfile', $position );
write_file( 'lastchunk', $last_chunk );

也许下面的内容会对你有所帮助:

在每个-- End --标记之后分割文件。

使用简单的递增后缀创建新文件。
use strict;
use warnings;
use autodie;
my $file = shift;
my $i = 0;
my $fh;
open my $infh, '<', $file;
while (<$infh>) {
    open $fh, '>', $file . '.' . ++$i if !$fh;
    print $fh $_;
    undef $fh if /^-- END --/;
}

遗憾的是,没有相应的truncate来从文件开头删除数据。

如果您真的希望分阶段完成此操作,那么我建议您只需在最后读取的位置tell,以便在准备输出另一个文件时可以seek

您可以使用flip-flop运算符来获取以下模式之间的内容:

use File::Slurp;
my @text = read_file( 'filename' ) ;
foreach my $line (@text){
  if ($line =~ /Start/ .. /End/) {
    # do stuff with $line
    print $line; # or so
  }
}

当你的文件很大的时候,要小心不要一次吞掉整个文件!

最新更新