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

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

./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?

Спасибо за ваш совет.

EDIT

Вот фиксированный код:

#!/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 Ответ

2 голосов
/ 10 марта 2011

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

foreach (sort keys %handles) {
    my $line = readline $handles{$_};
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...