我正在尝试拆分一个巨大的文本文件(~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
}
}
当你的文件很大的时候,要小心不要一次吞掉整个文件!