在 Perl 中将文件转换为字符串的最佳方法是什么?

问题描述 投票:0回答:17

是的,有不止一种方法可以做到这一点,但必须有一种规范的或最有效或最简洁的方法。我会添加我知道的答案,看看哪些内容会渗透到顶部。

需要明确的是,问题是如何最好地将文件的内容读取到字符串中。 每个答案一个解决方案。

perl string file-io file
17个回答
76
投票

这个怎么样:

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

预计到达时间:注意 File-Slurp 的 Bug #83126:编码 (UTF-8) 的安全漏洞。我现在推荐使用 File::Slurper (免责声明:我写的),也是因为它在编码方面有更好的默认值:

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

路径::微小:

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

48
投票
我喜欢使用

do

 块来执行此操作,在其中定位 
@ARGV
,这样我就可以使用菱形运算符来为我执行文件魔法。 

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

如果您需要更强大一点,您可以轻松地将其变成子例程。

如果您需要真正强大的东西来处理各种特殊情况,请使用File::Slurp。即使您不打算使用它,也请查看源代码以了解它必须处理的所有古怪情况。 File::Slurp 有一个大的安全问题,但看起来并没有解决方案。部分原因是它无法正确处理编码。即使我的快速回答也有这个问题。如果您需要处理编码(可能是因为默认情况下您没有将所有内容都设置为 UTF-8),则这会扩展为:

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

如果您不需要更改文件,您也许可以使用

File::Map



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

11
投票
需要考虑的事情(特别是与其他解决方案相比):

    词法文件句柄
  1. 缩小范围
  2. 减少魔法
所以我得到:

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

我不太喜欢魔法<>,除非实际使用魔法<>。与其伪造它,为什么不直接使用 open call 呢?这并不需要太多工作,而且很明确。 (真正的魔法 <>,特别是在处理“-”时,要完美模拟需要做更多的工作,但我们无论如何都不会在这里使用它。)


10
投票
字符串的 mmap(内存映射)在以下情况下可能很有用:

    有非常大的字符串,您不想将其加载到内存中
  • 想要盲目快速的初始化(访问时会获得渐进的 I/O)
  • 可以随机或延迟访问字符串。
  • 可能想要更新字符串,但只是扩展它或替换字符:
#!/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 月

Sys::Mmap 替换为 File::Map 后,以下内容应该非常等效

#!/usr/bin/perl use warnings; use strict; use File::Map qw{map_file}; map_file(my $str => '/tmp/words', '+<'); print substr($str, 100, 20);
    

8
投票
这既不快,也不独立于平台,而且确实很邪恶,但它很短(我在 Larry Wall 的代码中看到了这一点;-):

my $contents = `cat $file`;

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


8
投票
use Path::Class; file('/some/path')->slurp;
    

7
投票
{ open F, $filename or die "Can't read $filename: $!"; local $/; # enable slurp mode, locally. $file = <F>; close F; }
    

6
投票
use IO::All; # read into a string (scalar context) $contents = io($filename)->slurp; # read all lines an array (array context) @lines = io($filename)->slurp;
    

6
投票
对于单行代码,您通常可以使用

-0

开关
(与-n
)让perl一次读取整个文件(如果文件不包含任何空字节):

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

如果是二进制文件,你可以使用

-0777

:

perl -n0777e 'print length' filename
    


3
投票
这里对最流行的方法进行了很好的比较:

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


3
投票
没有人说任何有关 read 或 sysread 的事情,所以这里有一个简单快速的方法:

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

1
投票
最差方法的候选者! (见评论。)

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

1
投票
调整特殊记录分隔符变量

$/



undef $/; open FH, '<', $filename or die "$!\n"; my $contents = <FH>; close FH;
    

0
投票
open(IN, "<$filename"); $contents = join('', <IN>); close(IN);
详情:

<IN>

 是一个文件描述符,如果分配给列表变量/上下文,则返回行列表(也称为数组)。

join

 采用分隔符和行列表,并返回所有行连接在一起的字符串。来源:
https://perldoc.perl.org/functions/join)。

open

,文件名前缀为“
<" opens the file in read-mode.

我经常使用 join 结构来表达单行,例如

perl -e '$_=join("",<>);s/multiline_regex/replacement_string/gms;print'

。 m/s 选项支持多行正则表达式,请参阅 
https://perldoc.perl.org/perlre

© www.soinside.com 2019 - 2024. All rights reserved.