什么是在Perl中将文件转换为string的最佳方式?

是的, 有很多方法可以做到这一点,但必须有一个规范或最有效或最简洁的方法。 我会添加我所知道的答案,看看什么渗透到顶端。

要清楚,问题是如何最好地将文件的内容读入string。 每个答案一个解决scheme

这个怎么样:

use File::Slurp; my $text = read_file($filename); 

ETA:请注意Bug#83126的File-Slurp:带编码的安全漏洞(UTF-8) 。 我现在推荐使用File :: Slurper (免责声明:我写它),也因为它有更好的编码默认值:

 use File::Slurper 'read_text'; my $text = read_text($filename); 

或path::微小 :

 use Path::Tiny; path($filename)->slurp_utf8; 

我喜欢用一个do块来完成这个工作,在这个块中我定位@ARGV这样我就可以使用钻石算子为我做文件魔法了。

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

如果你需要这个更健壮,你可以很容易地把它变成一个子程序。

如果你需要一些强大的处理各种特殊情况的东西,使用File :: Slurp 。 即使你不打算使用它,看看源代码,看看它必须处理的所有古怪的情况。 File :: Slurp有一个很大的安全问题 ,看起来没有解决scheme。 部分原因是它没有正确处理编码。 即使我的快速答案有这个问题。 如果你需要处理编码(也许是因为你没有默认做所有的UTF-8),那么这个扩展就是:

 my $contents = do { open my $fh, '<:encoding(UTF-8)', $file or die '...'; local $/; <$fh>; }; 

如果您不需要更改文件,则可以使用File :: Map 。

在编写File :: Slurp (这是最好的方法)的时候,Uri Guttman在许多方面做了很多研究,而且最有效率。 他在这里写下他的发现 ,并将它们合并到File :: Slurp中。

 open(my $f, '<', $filename) or die "OPENING $filename: $!\n"; $string = do { local($/); <$f> }; close($f); 

需要考虑的事情(尤其是与其他解决scheme相比):

  1. 词汇文件句柄
  2. 缩小范围
  3. 减less魔法

所以我得到:

 my $contents = do { local $/; open my $fh, $filename or die "Can't open $filename: $!"; <$fh> }; 

除了实际使用魔法<>以外,我不是魔法的狂热粉丝。 为什么不直接使用公开电话? 这不是更多的工作,是明确的。 (真正的魔法<>,特别是在处理“ – ”时,要完美地模仿更多的工作,但是我们在这里并没有使用它。)

在以下情况下,string的mmap(内存映射)可能会有用:

  • 有非常大的string,你不想加载到内存中
  • 想要一个盲目的快速初始化(你获得逐步的访问I / O)
  • 有随机或懒惰的访问string。
  • 可能要更新string,但只是扩展或replace字符:
 #!/usr/bin/perl use warnings; use strict; use IO::File; use Sys::Mmap; sub sip { my $file_name = shift; my $fh; open ($fh, '+<', $file_name) or die "Unable to open $file_name: $!"; my $str; mmap($str, 0, PROT_READ|PROT_WRITE, MAP_SHARED, $fh) or die "mmap failed: $!"; return $str; } my $str = sip('/tmp/words'); print substr($str, 100,20); 

更新:2012年5月

用File :: MapreplaceSys :: Mmap后,下面的内容相当相似

 #!/usr/bin/perl use warnings; use strict; use File::Map qw{map_file}; map_file(my $str => '/tmp/words', '+<'); print substr($str, 100, 20); 
 use Path::Class; file('/some/path')->slurp; 
 { open F, $filename or die "Can't read $filename: $!"; local $/; # enable slurp mode, locally. $file = <F>; close F; } 
 use IO::All; # read into a string (scalar context) $contents = io($filename)->slurp; # read all lines an array (array context) @lines = io($filename)->slurp; 

请参阅Perl6 :: Slurp的总结,它非常灵活,通常只需很less的努力就能做正确的事情。

这个既不快,也不平台独立,真的很邪恶,但很短(我在Larry Wall的代码中已经看到了这一点;-):

  my $contents = `cat $file`; 

孩子们,不要在家里这样做;-)。

这是一个很好的比较最stream行的方法来做到这一点:

http://poundcomment.wordpress.com/2009/08/02/perl-read-entire-file/

没有人会说读或读系统,所以这是一个简单快捷的方法:

 my $string; { open my $fh, '<', $file or die "Can't open $file: $!"; read $fh, $string, -s $file; # or sysread close $fh; } 

对于单行程序,您通常可以使用-0开关 (带-n )使perl一次读取整个文件(如果文件不包含空字节):

 perl -n0e 'print "content is in $_\n"' filename 

如果是二进制文件,则可以使用-0777

 perl -n0777e 'print length' filename 

候选人最糟糕的做法! (见评论)

 open(F, $filename) or die "OPENING $filename: $!\n"; @lines = <F>; close(F); $string = join('', @lines); 

调整特殊logging分隔符variables$/

 undef $/; open FH, '<', $filename or die "$!\n"; my $contents = <FH>; close FH; 
 # Takes the name of a file and returns its entire contents as a string. sub getfile { my($filename) = @_; my($result); open(F, $filename) or die "OPENING $filename: $!\n"; while(<F>) { $result .= $_; } close(F); return $result; }