-1

我认为我遇到了 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
                }
            }

它死在“死在这里!!” 死,在读取第二个文件的 3,413 个字符后。

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

4

1 回答 1

2

问题几乎可以肯定是因为数据不在要读取的文件中。

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

您应该检查close呼叫的成功状态,如下所示

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

除此之外,对如此少量的数据使用临时文件而不是简单地将其全部保存在内存中是否明智值得怀疑。此外:

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

  • 您对变量名称的选择是不稳定的。$i文件名?而$o对于 - 呃 - 什么?$buff会很好,只是它是一个名义缓冲区而不是缓冲区 istelf 的大小

  • 您应该使用具有以下三参数形式的词法文件句柄openopen my $fil, '<', $i or die "$!: $i";

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

  • 我认为一个简单的split /\t/会比你正在使用的正则表达式更好。%site_nu看起来像这样的数组散列会更好$site_nu{$j} = [$mirna, $target, $start, $end, $site, $comp_p]

  • 将换行符放在die字符串的末尾会阻止 perl 显示有关源文件和数据文件以及行号的信息,这在您调试时可能很有用

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

于 2013-03-31T14:04:49.083 回答