124

.html ファイルを 1 つの大きな長い文字列として開こうとしています。これは私が持っているものです:

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

その結果:

<!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">

このようにして、ドキュメント全体をより簡単に検索できます。

4

15 に答える 15

100

私は次のようにします:

my $file = "index.html";
my $document = do {
    local $/ = undef;
    open my $fh, "<", $file
        or die "could not open $file: $!";
    <$fh>;
};

open の 3 引数バージョンの使用に注意してください。これは、引数が 2 つ (または 1 つ) の古いバージョンよりもはるかに安全です。レキシカルファイルハンドルの使用にも注意してください。レキシカル ファイルハンドルは、多くの理由から、古いベアワード バリアントよりも優れています。ここでは、そのうちの 1 つを利用しています。範囲外になると閉じます。

于 2009-06-05T01:28:49.307 に答える
85

追加:

 local $/;

ファイルハンドルから読み取る前。ファイル全体を一度に読み込むにはどうすればよいですか? を参照してください。、 また

$ perldoc -q "ファイル全体"

およびのファイルハンドルに関連する変数を参照してください。perldoc perlvarperldoc -f local

ちなみに、スクリプトをサーバーに配置できる場合は、必要なすべてのモジュールを使用できます。自分のモジュール/ライブラリ ディレクトリを保持するにはどうすればよいですか? を参照してください。.

さらに、Path::Class::Fileを使用すると、 slurpspewを実行できます。

Path::Tinyは、 、およびそれらの対応するメソッドなどslurpslurp_rawslurp_utf8さらに便利なメソッドを提供します。spew

于 2009-06-05T00:18:40.433 に答える
81

File::Slurpの場合:

use File::Slurp;
my $text = read_file('index.html');

はい、あなたも CPAN を使用できます

于 2009-06-05T08:55:02.027 に答える
57

すべての投稿は、やや慣用的ではありません。イディオムは次のとおりです。

open my $fh, '<', $filename or die "error opening $filename: $!";
my $data = do { local $/; <$fh> };

ほとんどの場合、 $/ を に設定する必要はありませんundef

于 2009-06-05T03:20:56.977 に答える
19

perlfaq5から: ファイル全体を一度に読み込むにはどうすればよいですか? :


File::Slurp モジュールを使用して、1 つのステップでそれを行うことができます。

use File::Slurp;

$all_of_it = read_file($filename); # entire file in scalar
@all_lines = read_file($filename); # one line per element

ファイル内のすべての行を処理する慣習的な Perl のアプローチは、一度に 1 行ずつ処理することです。

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

これは、ファイル全体を行の配列としてメモリに読み込み、一度に 1 つの要素を処理するよりもはるかに効率的です。誰かがこれをしているのを見たときはいつでも:

@lines = <INPUT>;

一度にすべてをロードする必要がある理由について、じっくりと考える必要があります。それはスケーラブルなソリューションではありません。また、標準の Tie::File モジュール、または DB_File モジュールの $DB_RECNO バインディングを使用する方が楽しいかもしれません。これにより、配列をファイルに関連付けることができるため、配列が要素にアクセスすると、実際にはファイル内の対応する行にアクセスできます。 .

ファイルハンドルの内容全体をスカラーに読み取ることができます。

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

これにより、レコード区切りが一時的に定義解除され、ブロックの終了時にファイルが自動的に閉じられます。ファイルが既に開いている場合は、これを使用してください。

$var = do { local $/; <INPUT> };

通常のファイルの場合は、読み取り機能も使用できます。

read( INPUT, $var, -s INPUT );

3 番目の引数は、INPUT ファイルハンドルのデータのバイト サイズをテストし、そのバイト数をバッファ $var に読み込みます。

于 2009-06-05T17:06:47.283 に答える
8

簡単な方法は次のとおりです。

while (<FILE>) { $document .= $_ }

もう 1 つの方法は、入力レコード区切り記号「$/」を変更することです。グローバル レコード セパレータの変更を避けるために、ベア ブロックでローカルに実行できます。

{
    open(F, "filename");
    local $/ = undef;
    $d = <F>;
}
于 2009-06-05T00:12:26.217 に答える
7

(jrockwayの回答を参照)に設定$/するかundef、ファイルのすべての行を連結します。

$content = join('', <$fh>);

それをサポートするすべてのPerlバージョンのファイルハンドルにスカラーを使用することをお勧めします。

于 2009-06-05T07:24:24.050 に答える
4

別の可能な方法:

open my $fh, '<', "filename";
read $fh, my $string, -s $fh;
close $fh;
于 2013-05-12T00:43:03.917 に答える
3

<FILE>スカラーコンテキストで評価しているため、ダイヤモンド演算子から最初の行のみを取得しています。

$document = <FILE>; 

リスト/配列コンテキストでは、ひし形演算子はファイルのすべての行を返します。

@lines = <FILE>;
print @lines;
于 2009-06-05T17:18:45.893 に答える
2

よりスマートな方法があっても、誰でも何が起こるかを理解できるように、私は最も簡単な方法でそれを行います。

my $text = "";
while (my $line = <FILE>) {
    $text .= $line;
}
于 2014-05-08T20:07:08.617 に答える
2

これは、そうしない方法についてのより多くの提案です。かなり大きな Perl アプリケーションでバグを見つけるのに苦労しました。ほとんどのモジュールには独自の構成ファイルがありました。構成ファイル全体を読むために、インターネット上のどこかで次の Perl の行を見つけました。

# Bad! Don't do that!
my $content = do{local(@ARGV,$/)=$filename;<>};

前に説明したように、行区切りを再割り当てします。ただし、STDIN も再割り当てします。

これには少なくとも 1 つの副作用があり、見つけるのに何時間もかかりました: 暗黙的なファイル ハンドルを適切に閉じません (まったく呼び出さないためclose)。

たとえば、次のようにします。

use strict;
use warnings;

my $filename = 'some-file.txt';

my $content = do{local(@ARGV,$/)=$filename;<>};
my $content2 = do{local(@ARGV,$/)=$filename;<>};
my $content3 = do{local(@ARGV,$/)=$filename;<>};

print "After reading a file 3 times redirecting to STDIN: $.\n";

open (FILE, "<", $filename) or die $!;

print "After opening a file using dedicated file handle: $.\n";

while (<FILE>) {
    print "read line: $.\n";
}

print "before close: $.\n";
close FILE;
print "after close: $.\n";

結果:

After reading a file 3 times redirecting to STDIN: 3
After opening a file using dedicated file handle: 3
read line: 1
read line: 2
(...)
read line: 46
before close: 46
after close: 0

$.奇妙なことに、ファイルごとに行カウンターが 1 ずつ増えます。リセットされず、行数は含まれません。また、別のファイルを開いたときに、少なくとも 1 行が読み込まれるまではゼロにリセットされません。私の場合、私は次のようなことをしていました:

while($. < $skipLines) {<FILE>};

この問題により、ライン カウンタが適切にリセットされなかったため、条件は false でした。これがバグなのか、単に間違ったコードなのかはわかりません...また、close;oderを呼び出しclose STDIN;ても役に立ちません。

この判読不能なコードを、open、string concatenation、および close を使用して置き換えました。ただし、代わりに明示的なファイル ハンドルを使用するため、Brad Gilbert によって投稿されたソリューションも機能します。

先頭の 3 行は、次のように置き換えることができます。

my $content = do{local $/; open(my $f1, '<', $filename) or die $!; my $tmp1 = <$f1>; close $f1 or die $!; $tmp1};
my $content2 = do{local $/; open(my $f2, '<', $filename) or die $!; my $tmp2 = <$f2>; close $f2 or die $!; $tmp2};
my $content3 = do{local $/; open(my $f3, '<', $filename) or die $!; my $tmp3 = <$f3>; close $f3 or die $!; $tmp3};

ファイルハンドルを適切に閉じます。

于 2012-02-20T10:48:24.683 に答える
0

サブルーチンを簡単に作成できます。

#Get File Contents
sub gfc
{
    open FC, @_[0];
    join '', <FC>;
}
于 2013-12-30T16:44:52.697 に答える