我正在尝试拆分一个非常规则的大文本文件(大约5亿行文本),如下所示:
-- Start ---
blah blah
-- End --
-- Start --
blah blah
-- End --
...
其中......暗示重复模式,“blah blah”具有可变长度~2000行。我想分开第一个
-- Start --
blah blah
-- End --
阻塞到一个单独的文件中并将其从FASTEST中的原始文件中删除(运行时,假设我将运行这么多次)可能的方式。
理想的解决方案是从原始文件中删除初始块并将其粘贴到新文件中,而不加载巨大的初始文件的尾部。
我用以下方式尝试了csplit:
csplit file.txt /End/+1
这是一种有效的方法,但在时间上效率不高。
编辑:如果我们从文件中删除最后一个“开始结束”块而不是第一个块,是否有解决方案?
答案 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
}
}
当你的文件很大时,要小心一次啜饮整个文件!