54

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

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

4

16 回答 16

75

这个怎么样:

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

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

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

Path::Tiny

use Path::Tiny;
path($filename)->slurp_utf8;
于 2008-10-15T21:59:42.997 回答
47

我喜欢使用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

于 2008-10-15T22:30:49.767 回答
35

在编写File::Slurp(这是最好的方式)时,Uri Guttman 对多种 slurp 方式进行了大量研究,哪种方式最有效。他在这里写下了他的发现并将其合并到 info File::Slurp。

于 2008-10-18T08:35:58.437 回答
24
open(my $f, '<', $filename) or die "OPENING $filename: $!\n";
$string = do { local($/); <$f> };
close($f);
于 2008-10-15T21:59:40.110 回答
11

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

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

所以我得到:

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

我不是魔法 <> 的忠实粉丝,除非实际使用魔法 <>。与其伪装出来,不如直接使用 open 调用?这不是更多的工作,而且是明确的。(真正的魔法<>,尤其是在处理“-”时,要完美模拟要付出更多的工作,但无论如何我们都不会在这里使用它。)

于 2008-10-15T22:38:38.770 回答
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);
于 2008-10-16T04:17:13.063 回答
8
use Path::Class;
file('/some/path')->slurp;
于 2008-12-08T03:30:05.273 回答
7
{
  open F, $filename or die "Can't read $filename: $!";
  local $/;  # enable slurp mode, locally.
  $file = <F>;
  close F;
}
于 2008-10-15T21:59:55.227 回答
7

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

 my $contents = `cat $file`;

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

于 2008-10-16T06:44:44.030 回答
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;
于 2011-08-10T20:09:04.453 回答
4

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

于 2008-10-15T22:19:39.120 回答
3

以下是最流行的方法的一个很好的比较:

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

于 2009-11-18T05:33:15.910 回答
3

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

my $string;
{
    open my $fh, '<', $file or die "Can't open $file: $!";
    read $fh, $string, -s $file;   # or sysread
    close $fh;
}
于 2012-04-11T13:05:13.063 回答
3

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

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

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

perl -n0777e 'print length' filename
于 2014-10-28T12:36:29.417 回答
1

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

open(F, $filename) or die "OPENING $filename: $!\n";
@lines = <F>;
close(F);
$string = join('', @lines);
于 2008-10-15T22:01:10.390 回答
1

调整特殊记录分隔符变量$/

undef $/;
open FH, '<', $filename or die "$!\n";
my $contents = <FH>;
close FH;
于 2015-05-28T22:35:14.773 回答