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

Bri*_*anH 44 io perl file perl-io

请注意 - 我不是在寻找打开/读取文件的"正确"方式,也不是每次都打开/读取文件的方式.我只是想知道大多数人使用的方式,并且可能同时学习一些新方法:)*

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

我以前打开这样的文件:

my $input_file = "/path/to/my/file";
open INPUT_FILE, "<$input_file"  || die "Can't open $input_file: $!\n";
Run Code Online (Sandbox Code Playgroud)

但我认为错误捕获存在问题.

添加括号似乎可以修复错误捕获:

open (INPUT_FILE, "<$input_file")  || die "Can't open $input_file: $!\n";
Run Code Online (Sandbox Code Playgroud)

我知道你也可以给一个变量分配一个文件句柄,所以不像我上面那样使用"INPUT_FILE",我可以使用$ input_filehandle - 这样更好吗?

对于读取文件,如果它很小,那么globbing有什么问题吗?

my @array = <INPUT_FILE>;
Run Code Online (Sandbox Code Playgroud)

要么

my $file_contents = join( "\n", <INPUT_FILE> );
Run Code Online (Sandbox Code Playgroud)

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

my @array;
while (<INPUT_FILE>) {
  push(@array, $_);
}
Run Code Online (Sandbox Code Playgroud)

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

JSB*_*ոգչ 59

没有通用标准,但有理由更喜欢这样或那样.我的首选形式是:

open( my $input_fh, "<", $input_file ) || die "Can't open $input_file: $!";
Run Code Online (Sandbox Code Playgroud)

原因是:

  • 您立即报告错误.(如果这是你想要的,请将"die"替换为"警告".)
  • 您的文件句柄现在已被引用计数,因此一旦您不使用它,它将自动关闭.如果使用全局名称INPUT_FILEHANDLE,则必须手动关闭该文件,否则它将保持打开状态直到程序退出.
  • 读模式指示符"<"与$ input_file分开,提高了可读性.

如果文件很小并且您知道您想要所有行,则以下内容非常好:

my @lines = <$input_fh>;
Run Code Online (Sandbox Code Playgroud)

如果需要将所有行作为单个字符串处理,您甚至可以执行此操作:

my $text = join('', <$input_fh>);
Run Code Online (Sandbox Code Playgroud)

对于长文件,您需要使用while迭代行,或使用read.

  • 还要考虑`使用autodie;`这将使你的IO操作默认致命.比在任何地方写'或死'更容易. (5认同)
  • 我仍然认为这是样板.只需使用`File :: Slurp`或`Tie :: File`即可. (2认同)

Ken*_*ric 15

如果您希望将整个文件作为单个字符串,则无需迭代它.

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;
}
Run Code Online (Sandbox Code Playgroud)

以上满足perlcritic --brutal,这是测试'最佳实践':)的好方法.$input_file这里仍然没有定义,但其余的是犹太教徒.

  • `$ RS`与``/`相同,``English`为你设置.`$ /`是跟踪`<$ fh>`的`row seperator`值的变量,它与`get-line`或`$ fh-> getline()`的概念同义.本质上,它包含内部读取算法用于知道何时读取完整的"行"数据的值,并将其设置为"undef"意味着"没有标记指示完整的行",因此它读取整个归档为"行" (2认同)

pjf*_*pjf 14

不得不在任何地方写'或死'让我疯狂.我打开文件的首选方法如下:

use autodie;

open(my $image_fh, '<', $filename);
Run Code Online (Sandbox Code Playgroud)

虽然打字很少,但有很多重要的事情需要注意:

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

  • 我们正在使用open的三参数版本.这意味着,即使我们有一个包含字符,如一个有趣的文件名<,>或者|,Perl会仍然做正确的事.在OSCON的Perl Security教程中,我展示了一些让2个参数open变为行为异常的方法.本教程的注释可从Perl Training Australia免费下载.

  • 我们正在使用标量文件句柄.这意味着我们不会巧合地关闭其他人的同名文件句柄,如果我们使用包文件句柄就会发生这种情况.它还意味着strict可以发现拼写错误,如果超出范围,我们的文件句柄将自动清除.

  • 我们正在使用有意义的文件句柄.在这种情况下,我们似乎要写一个图像.

  • 文件句柄以_fh.结尾.如果我们看到我们像常规标量一样使用它,那么我们就知道它可能是一个错误.


Dav*_*sky 11

如果您的文件足够小,可以将整个内容读入内存,请使用File :: Slurp.它使用非常简单的API读取和写入完整文件,并且它会执行所有错误检查,因此您不必这样做.


bri*_*foy 6

没有最好的方法来打开和读取文件.这是一个错误的问题.文件中有什么?您在任何时候需要多少数据?您是否一次需要所有数据?您需要对数据做什么?在考虑如何打开和读取文件之前,您需要弄清楚这些.

您现在正在做的任何事情都会导致您出现问题吗?如果没有,你有没有更好的问题要解决?:)

你的大多数问题仅仅是语法,这些都在Perl文档中得到了解答(特别是(perlopentut).你可能也想学习Perl,它可以回答你在问题中遇到的大部分问题.

祝好运, :)


Axe*_*man 5

对于OO,我喜欢:

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;
Run Code Online (Sandbox Code Playgroud)


小智 5

确实,有很多最好的方法可以在Perl中打开文件

$files_in_the_known_universe * $perl_programmers
Run Code Online (Sandbox Code Playgroud)

......但是看看谁通常以哪种方式做到这一点仍然很有趣.我首选的啜饮形式(一次读取整个文件)是:

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);
Run Code Online (Sandbox Code Playgroud)

当逐行时:

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

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


Sva*_*nte 5

我曾经使用过

open (FILEIN, "<", $inputfile) or die "...";
my @FileContents = <FILEIN>;
close FILEIN;
Run Code Online (Sandbox Code Playgroud)

定期样板。如今,我File::Slurp用于我想完全保存在内存中的小文件,以及Tie::File我想可扩展寻址的大文件和/或我想就地更改的文件。