疑似Perl缓冲问题

时间:2013-03-31 13:24:22

标签: perl buffering

我认为我有一个Perl缓冲问题,因为我需要读取和解析大文本文件(由我自己在前面的代码行中创建),以便最终在另一个文件中打印。

在某些时候,在读取了包含90,855行和第二个文件的其他文件的文件之后,脚本没有完全读取文件的一行。

我已计算在此之前读取的字符数:233,467,因此在读取文件的下一行之前尝试刷新缓冲区并休眠。它不起作用。

有什么建议吗?

这是我的代码:

foreach $i (@files) {

    my $buff = 0;

    print "Analyzing $i\n";
    sleep(1);
    $program = $1 if $i =~ /(\w+)_SITES/;

    open(FIL, $i) or die "$!: $i\n";
    while (<FIL>) {

        $buff += length($_);
        if ($buff >= 230000) {  #FLUSH THE BUFFER, NOT WORKING!!!
            $buff = 0;
            sleep(1);
            select((select(FIL), $| = 1)[0]);
        }

        undef($a);
        unless ($. == 1) {
            if ($o == 0) {
                if (/^\d+\t(\S+)\t(\S+)\t(\d+)\t(\d+)\t(\S+)\t(\S+)\t(.*)/) {
                    $mirna  = $1;
                    $target = $2;
                    $start  = $3;
                    $end    = $4;
                    $site   = $5;
                    $comp_p = $6;
                    $a      = $7;
                    $j      = "${mirna}_${target}_${start}_$end";
                    $site_nu{$j} = "$mirna\t$target\t$start\t$end\t$site\t$comp_p";    # Store each site in a hash
                }
                else {   #DIES HERE!!!
                  die "$buff characters, in line $.:$_\n"
                }
            }
            else {
                if (/^\d+\t(\S+)\t(\S+)\t(\d+)\t(\d+)\t(\S+)\t(.*)/) {
                    $mirna       = $1;
                    $target      = $2;
                    $start       = $3;
                    $end         = $4;
                    $site        = $5;
                    $a           = $6;
                    $j           = "${mirna}_${target}_${start}_$end";
                    $site_nu{$j} = "$mirna\t$target\t$start\t$end\t$site";    # Store each site in a hash
                }
            }

它死于“DIES HERE !!”在读完第二个文件的3,413个字符后死掉。

这是因为正则表达式不起作用,因为只有一半的行在$ _。

1 个答案:

答案 0 :(得分:2)

问题几乎可以肯定,因为您的文件中没有数据可供阅读。

您说该文件是从代码的早期部分生成的。我怀疑你有一个缓冲问题那里。代码编写完文件后,使用close将剩余数据刷新到文件中,我猜这一切都会很好。

您应该检查close来电的成功状态,例如

close FILEHANDLE or die "Unable to close temporary file: $!";

除此之外,将临时文件用于如此小的数据量而不是简单地将其保存在内存中的智慧是值得怀疑的。另外:

  • 您必须始终 use strictuse warnings并使用my声明所有变量尽可能接近其第一个使用点。除非你选择在程序的顶部声明所有内容(一个非常糟糕的主意),否则你没有这样做

  • 您选择的变量名称不稳定。 $i是否有文件名?并$o为 - 呃 - 什么? $buff会很好,除非它是名义buffre的 size 而不是缓冲区istelf

  • 您应该使用词法文件句柄,其中包含open的{​​{1}}:open my $fil, '<', $i or die "$!: $i";

  • 如果您正确使用$|,则使用FILE->autoflush时更整洁,更易读,而不是交换选定的文件句柄并设置$|。要执行此操作,您需要在代码开头use IO::Handle,除非您运行Perl 5版本14或更高版本,并根据需要加载IO::File(因此IO::Handle

    < / LI>
  • 我认为一个简单的split /\t/会比你正在使用的正则表达式更好。对于像这样%site_nu

  • $site_nu{$j} = [$mirna, $target, $start, $end, $site, $comp_p]的数组哈希看起来你会更好。
  • die字符串末尾添加换行符会阻止perl显示有关源和数据文件以及行号的信息,这在调试时可能很有用

  • 你会做自己,以及那些你寻求帮助的人,通过很好地格式化你的源代码来获得帮助。如果没有适当的缩进,很难分辨代码块的开始和结束位置