2

我正在编写一个只读取文件的脚本。我遇到的一个问题是,如果我传入一个路径(使用 Getoptions::Long),它会告诉我文件或目录不存在,即使它可以打印出文件名。例如:

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

没有这样的文件或目录:/Users/thomaswtsang/Dropbox/dev/test-monkey/perl/fileReader.pl 第 67 行的 f1.txt。

然后... 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

完全的!

我真的不明白为什么我会出现这种行为。权限问题?

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";

如果有更好的方法,请指出,谢谢!

4

2 回答 2

8
 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- 不else包含仅包含一个表达式的条件可以从

if (COND) {EXPR}

EXPR if COND;

我觉得更容易阅读。

接下来,readdir不将换行符附加到文件名。因此,从文件名末尾删除换行符是不必要和错误的——这些可能是某些文件系统中文件名的合法字符(1)。所以

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

是一个不必要的错误。

1:示例包括 Ext2–Ext4 系列(除/and之外的\0所有字符)、HFS(除 之外的所有字符:)、Posix 模式下的 NTFS(除/and之外的所有字符)\0和 Win32 模式下的 NTFS 还不允许使用\, *, ?, :, ", <, >, |

在 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-01T10:04:47.237 回答
1

$path您需要为来自的文件名添加前缀readdir,例如

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

以上为所有目录条目添加前缀,$path并从结果中删除所有目录(因为您不想打开它们)。

于 2013-06-01T10:10:46.687 回答