在Perl中打开和读取文件的最佳方式是什么?

请注意 – 我不是在寻找打开/读取文件的“正确”方式,也不是每次打开/读取文件的方式。 我只是想找出大多数人使用什么方式,也许在同一时间学习一些新的方法:)*

我的Perl程序中一个非常常见的代码块是打开一个文件并读取或写入。 我已经看到了很多这样做的方式,而且我这几年来执行这个任务的风格已经改变了。 我只是想知道什么是最好的 (如果有最好的方法)是这样做的?

我曾经打开过这样的文件:

my $input_file = "/path/to/my/file"; open INPUT_FILE, "<$input_file" || die "Can't open $input_file: $!\n"; 

但是我认为这有错误陷阱的问题。

添加括号似乎可以修复错误陷印:

 open (INPUT_FILE, "<$input_file") || die "Can't open $input_file: $!\n"; 

我知道你也可以将一个文件句柄分配给一个variables,所以不用像上面那样使用“INPUT_FILE”,我可以使用$ input_filehandle – 这样更好吗?

对于阅读文件,如果它很小,那么这个文件是否有什么问题呢?

 my @array = <INPUT_FILE>; 

要么

 my $file_contents = join( "\n", <INPUT_FILE> ); 

或者你应该总是循环,就像这样:

 my @array; while (<INPUT_FILE>) { push(@array, $_); } 

我知道有很多方法可以在perl中完成,我只是想知道在文件中是否有打开和读取的首选/标准方法?

没有通用的标准,但是有理由select这个或那个。 我最喜欢的forms是这样的:

 open( my $input_fh, "<", $input_file ) || die "Can't open $input_file: $!"; 

原因是:

  • 您立即报告错误。 (如果这是你想要的,用“警告”replace“死亡”。)
  • 您的文件句柄现在是引用计数的,所以一旦您不使用它,它将被自动closures。 如果使用全局名称INPUT_FILEHANDLE,则必须手动closures文件,否则它将保持打开状态,直到程序退出。
  • 读取模式指示符“<”与$ input_file分开,增加了可读性。

如果文件很小,并且你知道你想要所有行,以下是很棒的:

 my @lines = <$input_fh>; 

你甚至可以做到这一点,如果你需要处理所有行作为一个单一的string:

 my $text = join('', <$input_fh>); 

对于长文件,你会想用循环遍历while,或者使用read。

如果你想把整个文件作为单个string,那么就不需要遍历它。

 use strict; use warnings; use Carp; use English qw( -no_match_vars ); my $data = q{}; { local $RS = undef; # This makes it just read the whole thing, my $fh; croak "Can't open $input_file: $!\n" if not open $fh, '<', $input_file; $data = <$fh>; croak 'Some Error During Close :/ ' if not close $fh; } 

以上满足perlcritic --brutal ,这是一个很好的方式来testing'最佳实践':)。 $input_file在这里仍然没有定义,但其余的是犹太教。

不得不在任何地方写下“或死去”都会让我疯狂。 我喜欢打开文件的方式如下所示:

 use autodie; open(my $image_fh, '<', $filename); 

尽pipe打字很less,但还有很多重要的事情需要注意:

  • 我们正在使用autodie编译指示,这意味着如果出现问题,所有Perl的内置函数都会抛出exception。 它消除了在你的代码中写入or die ...的需要,它产生友好的,人类可读的错误消息,并且具有词汇范围。 它可以从CPAN获得。

  • 我们正在使用open的三参数版本。 这意味着,即使我们有一个有趣的文件名包含字符,如<>| ,Perl仍然会做正确的事情。 在OSCON的Perl安全教程中,我展示了许多方法让两参数open行为不当。 本教程的注释可从Perl Training Australia免费下载 。

  • 我们正在使用标量文件句柄。 这意味着我们不会一致地closures其他人的同名文件句柄,如果我们使用包文件句柄就会发生这种情况。 这也意味着strict可以发现错别字,并且如果超出范围,我们的文件句柄将被自动清除。

  • 我们正在使用有意义的文件句柄。 在这种情况下,它看起来像我们要写入一个图像。

  • 文件句柄以_fh 。 如果我们看到我们像普通的标量一样使用它,那么我们知道这可能是一个错误。

如果你的文件足够小,将整个内容读入内存是可行的,使用File :: Slurp 。 它使用一个非常简单的API来读取和写入完整的文件,再加上它所有的错误检查,所以你不必。

没有最好的方法来打开和读取文件。 问这个问题是错误的。 什么在文件中? 在任何时候你需要多less数据? 你一次需要所有的数据吗? 你需要怎样处理这些数据? 在考虑如何打开和读取文件之前,您需要先弄清楚这些问题。

你现在正在做什么,导致你的问题? 如果不是,你有没有更好的问题来解决? 🙂

大部分的问题只是语法,所有的Perl文档(特别是( peropentut ))都可以解决这个问题。你也可以select学习Perl ,它可以解决你的问题中的大部分问题。

祝你好运, :)

确实有很多最好的方式来打开Perl文件

 $files_in_the_known_universe * $perl_programmers 

…但是看谁通常是这样做还是很有意思的。 我喜欢的forms(一次读完整个文件)是:

 use strict; use warnings; use IO::File; my $file = shift @ARGV or die "what file?"; my $fh = IO::File->new( $file, '<' ) or die "$file: $!"; my $data = do { local $/; <$fh> }; $fh->close(); # If you didn't just run out of memory, you have: printf "%d characters (possibly bytes)\n", length($data); 

而当一行一行的时候:

 my $fh = IO::File->new( $file, '<' ) or die "$file: $!"; while ( my $line = <$fh> ) { print "Better than cat: $line"; } $fh->close(); 

注意当然是这样的:这些只是我为日常工作而致力于肌肉记忆的方法,它们可能根本不适合你想要解决的问题。

对于面向对象,我喜欢:

 use FileHandle; ... my $handle = FileHandle->new( "< $file_to_read" ); croak( "Could not open '$file_to_read'" ) unless $handle; ... my $line1 = <$handle>; my $line2 = $handle->getline; my @lines = $handle->getlines; $handle->close; 

我曾经用过

 open (FILEIN, "<", $inputfile) or die "..."; my @FileContents = <FILEIN>; close FILEIN; 

样板文件。 现在,我使用File::Slurp来存储我想要完全保存在内存中的小文件,以及Tie::File来存放我想要扩展的大文件和/或我想要更改的文件。

用一行读取整个文件$ file到variables$ text

 $text = do {local(@ARGV, $/) = $file ; <>}; 

或者作为一个function

 $text = load_file($file); sub load_file {local(@ARGV, $/) = @_; <>} 

如果这些程序只是为了您的生产力,无论什么作品! build立尽可能多的error handling,你认为你需要。

如果读取整个文件很大,可能不是长期执行任务的最佳方式,因此您可能需要在处理行时进行处理,而不是将其加载到数组中。

我从“语用程序员”(Hunt&Thomas)的一个章节中得到的一个提示是,在开始工作切片和切割之前,您可能希望让脚本为您保存文件的备份。

|| 运算符具有更高的优先级,因此在将结果发送到“open”之前先进行评估。在您提到的代码中,使用“或”运算符,而不会出现这个问题。

 open INPUT_FILE, "<$input_file" or die "Can't open $input_file: $!\n"; 

达米安康威这样做:

 $data = readline!open(!((*{!$_},$/)=\$_)) for "filename"; 

但我不推荐给你。