работа с файловыми дескрипторами в Perl - PullRequest
0 голосов
/ 27 августа 2010

Я пишу подпрограмму comparefiles в Perl, которая читает строку текста из одного файла (f1) и затем ищет его в другом (f2) обычным способом O(n^2).

sub comparefiles {
    my($f1, $f2) = @_;
    while(<f1>) {
        # reset f2 to the beginning of the file
        while(<f2>) {
        }
    }
}

sub someother {
    open (one, "<one.out");
    open (two, "<two.out");
    &comparefiles(&one, &two);
}

У меня два вопроса

  • Как передать файловые дескрипторы подпрограмме? В приведенном выше коде я использовал их в качестве скаляров. Это правильный путь?
  • Как сбросить указатель файла f2 на начало файла в позиции, отмеченной в комментарии выше?

Ответы [ 2 ]

8 голосов
/ 27 августа 2010

Прежде всего запускайте каждый раз, когда ваш скрипт:

use strict;
use warnings;

Используйте лексический дескриптор файла, откройте три аргумента и проверьте результат:

open my $fh1 , '<' , $filename1 or die "can't open '$filename1' for reading : $!";

Затем вы можете передать дескрипторы файлаsub:

comparefiles($fh1, $fh2);

Для перемотки файла используйте функцию поиска (perldoc -f seek)

seek $fh, 0, 0;
2 голосов
/ 27 августа 2010

Если файлы достаточно малы, чтобы поместиться в памяти, вы можете подумать о сохранении строк в хэше, что исключит необходимость поиска O(n^2).

В рамках существующего подходасоветую не вкладывать циклы чтения вашего файла - возможно, из эстетических соображений, если ничего больше.Вместо этого поместите внутренний цикл в подпрограмму.

use strict;
use warnings;

# Works for 2 or more files.
analyze_files(@ARGV);

sub analyze_files {
    my @file_names = @_;
    my @handles = map { open my $h, '<', $_; $h } @_;
    my $fh = shift @handles;

    while (my $line = <$fh>) {
        my @line_numbers = map { find_in_file($_, $line) } @handles;
        print join("\t", @line_numbers, $line);
    }
}

# Takes a file handle and a line to hunt for.
# Returns line number if the line is found.
sub find_in_file {
    my ($fh, $find_this) = @_;
    seek $fh, 0, 0;
    while (my $line = <$fh>){
        return $. if $line eq $find_this;
    }
    return -1; # Not found.
}
...