【发布时间】:2010-09-17 10:12:59
【问题描述】:
是的,There's More Than One Way To Do It,但必须有一个规范或最有效或最简洁的方法。我会添加我知道的答案,看看有什么内容会渗透到顶部。
要清楚,问题是如何最好地将文件的内容读入字符串。 每个答案一个解决方案。
【问题讨论】:
是的,There's More Than One Way To Do It,但必须有一个规范或最有效或最简洁的方法。我会添加我知道的答案,看看有什么内容会渗透到顶部。
要清楚,问题是如何最好地将文件的内容读入字符串。 每个答案一个解决方案。
【问题讨论】:
这个怎么样:
use File::Slurp;
my $text = read_file($filename);
预计到达时间:注意 Bug #83126 for File-Slurp: Security hole with encoding(UTF-8)。我现在推荐使用File::Slurper(免责声明:我写的),也是因为它在编码方面有更好的默认值:
use File::Slurper 'read_text';
my $text = read_text($filename);
use Path::Tiny;
path($filename)->slurp_utf8;
【讨论】:
Undefined subroutine &main::read_text。应该是use File::Slurper 'read_text';。 metacpan.org/pod/File::Slurper
我喜欢使用 do 块执行此操作,我在其中本地化 @ARGV,因此我可以使用菱形运算符为我执行文件魔术。
my $contents = do { local(@ARGV, $/) = $file; <> };
如果你需要它更健壮一点,你可以很容易地把它变成一个子例程。
如果您需要能够处理各种特殊情况的强大功能,请使用File::Slurp。即使您不打算使用它,也请查看源代码以了解它必须处理的所有古怪情况。 File::Slurp 有一个 big security problem 看起来没有解决方案。部分原因是它未能正确处理编码。即使我的快速回答也有这个问题。如果您需要处理编码(可能是因为默认情况下您没有将所有内容都设为 UTF-8),则此扩展为:
my $contents = do {
open my $fh, '<:encoding(UTF-8)', $file or die '...';
local $/;
<$fh>;
};
如果您不需要更改文件,您可以使用File::Map。
【讨论】:
my $contents = do {local (@ARGV,$/) = $file; <>};,用更少的字符写完全一样的东西:)
<> 的文件中,希望它从STDIN 读取。 <> 的行为不同于第一次调用和后续调用,并且由于我更改了第一次调用,因此我也更改了现有调用的行为(预期 <STDIN> 的行为 <>)。
在写File::Slurp(这是最好的方式)时,Uri Guttman 对多种啜饮方式进行了大量研究,哪种方式最有效。他写下了his findings here 并将它们合并到信息 File::Slurp。
【讨论】:
open(my $f, '<', $filename) or die "OPENING $filename: $!\n";
$string = do { local($/); <$f> };
close($f);
【讨论】:
需要考虑的事情(尤其是与其他解决方案相比时):
所以我得到:
my $contents = do {
local $/;
open my $fh, $filename or die "Can't open $filename: $!";
<$fh>
};
我不是魔法的忠实粉丝,除了实际使用魔法。与其伪装出来,不如直接使用 open 调用?这不是更多的工作,而且是明确的。 (真正的魔法,尤其是在处理“-”时,要完美模拟需要做更多的工作,但无论如何我们都不会在这里使用它。)
【讨论】:
字符串的mmap(内存映射)可能在以下情况下很有用:
#!/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);
【讨论】:
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;
}
【讨论】:
这既不快速,也不独立于平台,而且非常邪恶,但它很短(我在 Larry Wall 的代码中看到了这一点 ;-):
my $contents = `cat $file`;
孩子们,不要在家里这样做;-)。
【讨论】:
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 的摘要,它非常灵活,通常只需很少的努力就能做正确的事情。
【讨论】:
以下是最流行的方法的一个很好的比较:
http://poundcomment.wordpress.com/2009/08/02/perl-read-entire-file/
【讨论】:
没有人谈论 read 或 sysread,所以这里有一个简单快捷的方法:
my $string;
{
open my $fh, '<', $file or die "Can't open $file: $!";
read $fh, $string, -s $file; # or sysread
close $fh;
}
【讨论】:
对于单行,你通常可以使用the -0 switch(和-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);
【讨论】:
cat $filename" 不可用,这是完全合理的。低效是的!但这不一定是唯一的考虑因素。
调整特殊记录分隔符变量$/
undef $/;
open FH, '<', $filename or die "$!\n";
my $contents = <FH>;
close FH;
【讨论】: