在Perl中,如何将整个文件读入字符串?

god*_*yan 113 string perl slurp

我正在尝试将.html文件打开为一个很长的字符串.这就是我所拥有的:

open(FILE, 'index.html') or die "Can't read file 'filename' [$!]\n";  
$document = <FILE>; 
close (FILE);  
print $document;
Run Code Online (Sandbox Code Playgroud)

这导致:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN

但是,我希望结果看起来像:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

这样我就可以更轻松地搜索整个文档.

Cha*_*ens 94

我会这样做:

my $file = "index.html";
my $document = do {
    local $/ = undef;
    open my $fh, "<", $file
        or die "could not open $file: $!";
    <$fh>;
};
Run Code Online (Sandbox Code Playgroud)

注意使用open的三参数版本.它比旧的两个(或一个)参数版本更安全.还要注意使用词法文件句柄.由于许多原因,词法文件句柄比旧的裸字变体更好.我们在这里利用其中一个:当它们超出范围时它们会关闭.

  • 这可能是最好的非cpan'd方式,因为它使用3参数open以及将INPUT_RECORD_SEPARATOR($ /)变量本地化为最小的必需上下文. (9认同)

Sin*_*nür 77

加:

 local $/;
Run Code Online (Sandbox Code Playgroud)

在从文件句柄中读取之前.请参阅如何一次读取整个文件?, 要么

$ perldoc -q "entire file"

请参阅相关的文件句柄的变量perldoc perlvarperldoc -f local.

顺便说一句,如果您可以将脚本放在服务器上,则可以拥有所需的所有模块.请参阅如何保留自己的模块/库目录?.

另外,Path :: Class :: File允许你啜饮喷出.

路径::微小给出更加方便的方法,例如slurp,slurp_raw,slurp_utf8以及他们的spew同行.

  • 您应该解释本地化$ /将要做什么的影响以及它的目的是什么. (31认同)
  • 如果您不打算解释有关本地化`$ /`的任何内容,您应该添加链接以获取更多信息. (11认同)
  • 一步一步解释正在做什么:{local $ /; 此处提供了<$ fh>}:http://www.perlmonks.org/?node_id = 287647 (7认同)

Que*_*tin 75

使用File :: Slurp:

use File::Slurp;
my $text = read_file('index.html');
Run Code Online (Sandbox Code Playgroud)

是的,即使你可以使用CPAN.

  • @Dmitry — 所以安装模块。我从这个答案链接到的 metacpan 页面上有一个安装说明链接。 (2认同)

jro*_*way 49

所有帖子都略显不恰当.这个成语是:

open my $fh, '<', $filename or die "error opening $filename: $!";
my $data = do { local $/; <$fh> };
Run Code Online (Sandbox Code Playgroud)

大多数情况下,没有必要设置$/undef.

  • 对不起,不同意.当你想要改变魔术变量的实际行为时,更明确的是明确的; 这是一份意向声明.甚至文档也使用'local $/= undef'(参见http://perldoc.perl.org/perlsub.html#Temporary-Values-via-local()) (11认同)
  • `local $ foo = undef`只是Perl Best Practice(PBP)建议的方法.如果我们发布代码的嗤之以鼻,我认为尽最大努力明确表示将是一件好事. (3认同)
  • 向人们展示如何编写非惯用代码是一件好事吗?如果我在我正在编写的代码中看到"local $/= undef",我的第一个动作就是公开羞辱作者irc.(而且我对"风格"问题一般都不挑剔.) (2认同)

bri*_*foy 18

perlfaq5:如何一次性读取整个文件?:


您可以使用File :: Slurp模块一步完成.

use File::Slurp;

$all_of_it = read_file($filename); # entire file in scalar
@all_lines = read_file($filename); # one line per element
Run Code Online (Sandbox Code Playgroud)

处理文件中所有行的习惯Perl方法是一次一行:

open (INPUT, $file)     || die "can't open $file: $!";
while (<INPUT>) {
    chomp;
    # do something with $_
    }
close(INPUT)            || die "can't close $file: $!";
Run Code Online (Sandbox Code Playgroud)

这比将整个文件作为一个行数组读入内存然后一次处理一个元素要高效得多,这通常 - 如果不是几乎总是 - 是错误的方法.每当你看到有人这样做:

@lines = <INPUT>;
Run Code Online (Sandbox Code Playgroud)

你应该长时间地思考为什么你需要一次装满所有东西.这不是一个可扩展的解决方案.您可能还会发现使用标准的Tie :: File模块或DB_File模块的$ DB_RECNO绑定更有趣,它允许您将数组绑定到文件,以便访问数组实际访问文件中相应行的元素.

您可以将整个文件句柄内容读入标量.

{
local(*INPUT, $/);
open (INPUT, $file)     || die "can't open $file: $!";
$var = <INPUT>;
}
Run Code Online (Sandbox Code Playgroud)

这暂时取消了您的记录分隔符,并将在块退出时自动关闭该文件.如果文件已经打开,只需使用:

$var = do { local $/; <INPUT> };
Run Code Online (Sandbox Code Playgroud)

对于普通文件,您也可以使用读取功能.

read( INPUT, $var, -s INPUT );
Run Code Online (Sandbox Code Playgroud)

第三个参数测试INPUT文件句柄上数据的字节大小,并将许多字节读入缓冲区$ var.


小智 7

一个简单的方法是:

while (<FILE>) { $document .= $_ }
Run Code Online (Sandbox Code Playgroud)

另一种方法是更改​​输入记录分隔符"$ /".您可以在裸块中本地执行此操作以避免更改全局记录分隔符.

{
    open(F, "filename");
    local $/ = undef;
    $d = <F>;
}
Run Code Online (Sandbox Code Playgroud)


kix*_*ixx 7

设置$/undef(请参阅jrockway的答案)或者只连接所有文件的行:

$content = join('', <$fh>);
Run Code Online (Sandbox Code Playgroud)

建议在任何支持它的Perl版本上使用标量文件句柄.


Ger*_*mia 6

使用

 $/ = undef;
Run Code Online (Sandbox Code Playgroud)

$document = <FILE>;$/输入记录分隔符,默认为换行符。通过将其重新定义为undef,您表示没有字段分隔符。这称为“slurp”模式。

其他解决方案如undef $/and local $/(但不是my $/)重新声明 $/ ,从而产生相同的效果。


ech*_*cho 5

另一种可能的方式:

open my $fh, '<', "filename";
read $fh, my $string, -s $fh;
close $fh;
Run Code Online (Sandbox Code Playgroud)