Как объединить определенные столбцы из файлов в массив или хэш нескольких файловых дескрипторов, по одной строке за раз?

Начну с описания файлов, с которыми я работаю:

./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, каждый размером в несколько сотен МБ.

  2. Я хотел бы перебирать дескрипторы файлов, читая по одной строке с разделителями табуляции за раз. Я не могу считать все строки файлов в память.

  3. Как только я закончу перебирать дескрипторы файлов, я хотел бы split каждую строку, взять определенный столбец данных из каждого разделенного массива (например, пятое поле) и объединить данные в строку вывода.

  4. Повторяйте шаг 2 — захватите по одной строке из каждого дескриптора файла — до EOF.

Тогда я получу groupA/mergedOutput.mtx, groupB/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;
}

Спасибо за советы!


person Alex Reynolds    schedule 10.03.2011    source источник
comment
Это ваш последний прыжок из while или из foreach?   -  person William Pursell    schedule 10.03.2011
comment
На самом деле, foreach. Так что мне нужно добавить метку к блоку while, спасибо.   -  person Alex Reynolds    schedule 10.03.2011


Ответы (1)


Вы можете читать из файловых дескрипторов следующим образом:

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