如何合并数组中的文件或多个文件句柄的散列中的特定列,一次一行?

时间:2011-03-10 11:10:18

标签: perl file io glob filehandle

我将首先描述我正在使用的文件:

./groupA
    ./groupA/fileA.txt
    ./groupA/fileB.txt
    ./groupA/fileC.txt
    ./groupA/fileD.txt

./groupB
    ./groupB/fileA.txt
    ./groupB/fileB.txt
    ./groupB/fileC.txt

etc.

以下是我想做的事情:

  1. 我为每个groupI提供了一个散列或文件句柄数组,指向非常大的制表符分隔文本文件fileJ,每个文件大小几百MB。

  2. 我想循环遍历文件句柄,一次读取一个制表符分隔的行。 我无法将所有文件的行读入内存。

  3. 一旦我完成了文件句柄的循环,我就想split每行,从每个分割数组(例如第五个字段)中获取特定的数据列,然后合并数据到输出线。

  4. 重复步骤2 - 从每个文件句柄中抓取一行 - 直到EOF。

  5. 然后我会以groupA/mergedOutput.mtxgroupB/mergedOutput.mtx

    结束

    问题是我不知道如何正确地执行第2步和第3步。

    这是我到目前为止的代码:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use File::Glob qw(glob);
    
    my @groups = qw(groupA groupB groupC);
    my ($mergedOutputFn, %fileHandles);
    
    foreach my $group (@groups) {
        $mergedOutputFn = "$group/mergedOutput.mtx";
    
        # Step 1:
        # Make hash table of file handles
    
        foreach my $inputFn (<"$group/*.txt">) {
            open my $handle, '< $inputFn' or die "could not open $inputFn\n";
            $fileHandles{$inputFn} = $handle;
        }
    
        # Steps 2 and 3:
        # Grab a line from each file handle
        # Repeat until EOF
    
        while(1) {
            my @mergedOutputLineElements = ();
            foreach (sort keys %handles) {
                my $handle = $handles{$_};
                my $line = <$handle>;
                chomp($line);
                my @lineElements = split("\t", $line);
                push (@mergedOutputLineElements, $lineElements[4]);
                last if (! defined $line); # jump out of while loop
            }
            print Dumper join("\t", @mergedOutputLineElements);
        }
    
        # Step 4:
        # Close handles
    
        foreach (sort keys %handles) {
            close $handles{$_};
        } 
    }
    

    一个问题似乎是以下代码不起作用:

    foreach (sort keys %handles) {
        my $handle = $handles{$_};
        my $line = <$handle>;
        ...
    }
    

    如果我尝试打印出$line的值,那么我会得到GLOB值:

    print Dumper $line;
    ...
    GLOB(0x1d769f80)
    

    我如何处理错误$line,或者在Perl中有更简单的方法吗?

    感谢您的建议。

    修改

    这是固定代码:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use File::Glob qw(glob);
    
    my @groups = qw(groupA groupB groupC);
    my ($mergedOutputFn, %fileHandles);
    
    foreach my $group (@groups) {
        $mergedOutputFn = "$group/mergedOutput.mtx";
        open MERGE, "> $mergedOutputFn" or die "could not open handle to $mergedOutputFn\n";
    
        # Step 1:
        # Make hash table of file handles
    
        foreach my $inputFn (<"$group/*.txt">) {
            open my $handle, '< $inputFn' or die "could not open $inputFn\n";
            $fileHandles{$inputFn} = $handle;
        }
    
        # Steps 2 and 3:
        # Grab a line from each file handle
        # Repeat until EOF
    
        LINE: while(1) {
            my @mergedOutputLineElements = ();
            foreach (sort keys %handles) {
                my $handle = $handles{$_};
                my $line = readline $handle;
                last LINE if (! defined $line); # jump out of while loop
                chomp($line);
                my @lineElements = split("\t", $line);
                push (@mergedOutputLineElements, $lineElements[4]);
            }
            print MERGE join("\t", @mergedOutputLineElements);
        }
    
        # Step 4:
        # Close handles
    
        foreach (sort keys %handles) {
            close $handles{$_};
        } 
    
        close MERGE;
    }
    

    感谢您的提示!

1 个答案:

答案 0 :(得分:2)

你可以从这样的文件句柄中读取:

foreach (sort keys %handles) {
    my $line = readline $handles{$_};
    ...
}