perl-скрипт не может читать файл в других каталогах

72
12

Я пишу скрипт, который читает только файлы. Проблема, с которой я столкнулся, заключается в том, что если я передаю путь (используя Getoptions :: Long), он сообщает мне, что файл или каталог не существует, хотя он может напечатать мне имя файла. Например:

thomaswtsang @alfred: perl $ perl ~/Dropbox/dev/test-monkey/perl/fileReader.pl --path ~/Dropbox/dev/test-monkey/diff

Нет такого файла или каталога: f1.txt в /Users/thomaswtsang/Dropbox/dev/test-monkey/perl/fileReader.pl строке 67.

И затем... cd-ing в этот каталог...

thomaswtsang @alfred: diff $ perl ~/Dropbox/dev/test-monkey/perl/fileReader.pl --path ~/Dropbox/dev/test-monkey/diff

(1/3) Чтение f1.txt...

(2/3) Чтение f2.txt...

Читать 21 Bs

Complete!

Я не совсем понимаю, почему я получаю такое поведение. Разрешения выдаются?

my $path = shift;
my $run_in_fg = shift;
if (length($path) == 0){
if ($run_in_fg){print "Using current directory...\n";}
$path = cwd();
}
print $path . "\n";
opendir my $dir, $path or die "Cannot open directory: $!";
my @files = readdir $dir;
my $num_files = $#files;
my $i = 1;
my $total_size = 0;
$SIG{'INT'} = sub {print "\n";print_read_size($total_size); exit 1;};

foreach my $file (@files){
if ($file =~ m/^\.+$/){next;}
$file =~ s/[\r\n]+$//;
open FILE, "<", $file or die "$!:$file";
if ($run_in_fg){ print "($i/$num_files)Reading $file...\n";}
while (my $line = <FILE>){
#don't need to actually print to screen, just load to memory
}
$total_size += -s $file;
close FILE or die $!;
$i++;
}

print_read_size($total_size);
print "Complete!\n";

Если есть более подходящие подходы, пожалуйста, укажите, спасибо!

спросил(а) 2013-06-01T12:50:00+04:00 7 лет, 3 месяца назад
1
Решение
112

 open FILE, "<", $file or die "$!:$file";

Эта строка пытается открыть $file - в текущем каталоге. В частности, readdir возвращает имена файлов, а не пути. Следовательно, необходимо добавить правильный путь:

  my $filepath = "$path/$file";
open FILE, "<", $filepath or die "$!:$filepath";

Комментарии к стилю:

my $i = 1;
for my $file (@files){
...;
$i++;
}

лучше выражается как

for my $i (1 .. @files) {
my $file = $files[$i - 1];
...;
}

И if -conditions без else, содержащего только одно выражение, можно изменить из

if (COND) {EXPR}

в

EXPR if COND;

которые мне легче читать.

Затем readdir не добавляет новую readdir к именам файлов. Поэтому нет ненужных и неправильных удалять новые строки с конца имени файла - это могут быть юридические символы имен файлов в некоторых файловых системах (1) . Так

$file =~ s/[\r\n]+$//;

является ненужной ошибкой.

1: Примеры включают семейство Ext2-Ext4 (все символы , за исключением / и \0), HFS (все символы , за исключением :), NTFS в режиме Posix (все , кроме / и \0), и NTFS в режиме Win32 дополнительно запрещает \, *, ? , :, ", <, >, |.

В perl5, v10 и более поздних версиях,

print SOMETHING, "\n";

могут быть выражены как

use feature 'say'; # or use VERSION where VERSION >= 5.10

say SOMETHING;

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

open my $fh, "<", $filepath or die "$!:$filepath";
while(my $line = <$fh>) {
...;
}

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

ответил(а) 2013-06-01T13:04:00+04:00 7 лет, 3 месяца назад
57

Вам нужно префикс $path to filenames, который поступает из readdir, например

 my @files = grep { ! -d $_ } map { "$path/$_" } readdir $dir;

Вышеприведенные префиксы всех записей в каталоге с помощью $path и удаляют все каталоги из результата (потому что вы не хотите их открывать).

ответил(а) 2013-06-01T13:10:00+04:00 7 лет, 3 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема