首页 > 解决方案 > 扫描一个大的 .gz 文件并将它的字符串从一个已知单词(在文件中重复)中拆分出来,并将所有拆分后的字符串保存在一个 .txt 文件中

问题描述

我正在尝试编写一个 perl 脚本,在该脚本中我试图打开和读取一个 .gz 文件并将其从一个在该文件中重复多次的已知单词('.EOM')中拆分出来,并将所有拆分保存在一个.txt 或 .tmp 文件。该 .gz 文件非常非常大(以 GB 为单位)。我尝试了许多不同的方法,但每次最后都会显示以下错误。“panic:sv_setpvn 在 perl_gz1.pl 第 7 行,第 38417185 行以负 strlen 调用”这里 'per_gz1.pl' 是我的 perl 文件名,'line 101' 是我编写以下代码行的行:我的 @spl =split('.EOM',$join);

我不知道这是什么类型的错误以及如何解决它。任何人都可以帮助解决它吗?有没有其他方法可以在不出现此错误的情况下做同样的事情?提前致谢。我附上了我的完整代码。

我试过以下代码:

use strict ;
use warnings;
my $file = "/nfs/iind/disks/saptak/dsbnatrgd.scntcl.gz";
open(IN, "gzcat $file |",) or die "gunzip $file: $!";
my $join = join('',<IN>);
#print $join;
my @spl=split('.EOM',$join);
print @spl;
close IN;


use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ;
my $input = "/nfs/iind/disks/cpc_disk0025/saptak/dsbnatrgd.scntcl.gz";
my $output = "NEW1.tmp";
gunzip $input => $output or die "gunzip failed: $GunzipError\n";
my $data = join("", "NEW1.tmp");
#use File::Slurp;
#my $data = read_file("NEW1.tmp");
my @spl=split(/.EOM/,$data)

and

use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ;
use IO::File ;
my $input = new IO::File "</nfs/iind/disks/cpc_disk0025/saptak/dsbnatrgd.scntcl.gz" or die "Cannot open 'file1.txt.gz': $!\n" ;
my $buffer ;
gunzip $input => \$buffer or die "gunzip failed: $GunzipError\n";
print $buffer;
my @spl=split(".EOM",$buffer);

But same error is coming every time.

我希望数组@spl 每次都会在指定的单词/字符串处保存文件并输出打印它。这样我就可以继续使用这个数组@spl,但没有输出,并且输出屏幕上显示错误“panic:sv_setpvn call withnegative strlen at perl_gz1.pl line 7, line 38417185”。

标签: perl

解决方案


如果这是一次性工作,我可能会这样做:

zcat dsbnatrgd.scntcl.gz | perl -ne'sub newf{$n||="0000";$n++;open($fh,">","output_$n.txt")||die}$fh||newf();/(.*)\.EOM(.*)/ and print {$fh} $1 and newf() and print {$fh} $2 or print {$fh} $_'

output_nnnn.txt每次.EOM在某处看到an 时,这都会为您提供一个新文件。nnnn00010002以此类推。也可以在一行的.EOM中间看到,然后保留之前和之后的 .EOM 以及上一个文件中的最后一个字符串和下一个文件中的第一个字符串。

oneliner解释说:

sub newf{
  $n||="0000";
  $n++;                               #increase the filename counter
  open($fh,">","output_$n.txt")||die  #open a new output filehandler
}
$fh||newf();        # 1st input line: create $fh file handler if it dont exists
/(.*)\.EOM(.*)/     # if the input line have a .EOM mark, grab whats before and after
   and print {$fh} $1 #...and print the before on current file
   and newf()         #...and open new file
   and print {$fh} $2 #...and print the after .EOM to the new file
or print {$fh} $_     #or if no .EOM on current line, just print it to the current output file

(或者您的意思是 .EOM 标记在 .gz 文件中未压缩?在这种情况下,.gz 文件可能无效)

您的方法不起作用的原因可能是因为输入非常大。您提到 .gz 文件是一些 GB,然后输入可能比那个大几倍。我在这里的方法不会尝试一次将所有内容都保存在内存中,因此文件大小无关紧要。


推荐阅读