Начну с описания файлов, с которыми я работаю:
./groupA
./groupA/fileA.txt
./groupA/fileB.txt
./groupA/fileC.txt
./groupA/fileD.txt
./groupB
./groupB/fileA.txt
./groupB/fileB.txt
./groupB/fileC.txt
etc.
Вот что я хотел бы сделать:
У меня есть хэш или массив дескрипторов файлов для каждого
groupI
, указывающих на очень большие текстовые файлы с разделителями табуляцииfileJ
, каждый размером в несколько сотен МБ.Я хотел бы перебирать дескрипторы файлов, читая по одной строке с разделителями табуляции за раз. Я не могу считать все строки файлов в память.
Как только я закончу перебирать дескрипторы файлов, я хотел бы
split
каждую строку, взять определенный столбец данных из каждого разделенного массива (например, пятое поле) и объединить данные в строку вывода.Повторяйте шаг 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;
}
Спасибо за советы!
foreach
. Так что мне нужно добавить метку к блокуwhile
, спасибо. - person Alex Reynolds   schedule 10.03.2011