分割大文件的最佳方法

时间:2014-05-12 04:59:58

标签: regex perl file unix csplit

我正在尝试拆分一个非常规则的大文本文件(大约5亿行文本),如下所示:

-- Start ---

blah blah

-- End --

-- Start --

blah blah

-- End --

...

其中......暗示重复模式,“blah blah”具有可变长度~2000行。我想分开第一个

-- Start --

blah blah

-- End --

阻塞到一个单独的文件中并将其从FASTEST中的原始文件中删除(运行时,假设我将运行这么多次)可能的方式。

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

我用以下方式尝试了csplit:

csplit file.txt /End/+1 

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

编辑:如果我们从文件中删除最后一个“开始结束”块而不是第一个块,是否有解决方案?

3 个答案:

答案 0 :(得分:6)

如果您希望从原始文件中删除开头,则您别无选择,只能读取和写入文件的其余部分。要删除结尾(正如您在编辑中所建议的那样),效率会更高:

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 empty\n";
my $position = $fh->tell;
$fh->close;
truncate( 'inputfile', $position );
write_file( 'lastchunk', $last_chunk );

答案 1 :(得分:2)

以下内容可能会对您有所帮助:

在每个-- 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文件。

答案 2 :(得分:0)

您可以使用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
  }
}

当你的文件很大时,要小心一次啜饮整个文件!