web-dev-qa-db-ja.com

Perlでは、ファイル全体を文字列に読み込むにはどうすればよいですか?

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

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

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

111
goddamnyouryan

追加:

 local $/;

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

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

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

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

さらに、 Path :: Class :: File を使用すると、 Slurp および spew を使用できます。

Path :: Tiny は、 SlurpSlurp_rawSlurp_utf8 などのさらに便利なメソッドと、対応する spew を提供します。

76
Sinan Ünür

私はこのようにします:

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

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

93
Chas. Owens

File :: Slurp

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

はい、CPANを使用できます

75
Quentin

すべての投稿はやや非正統的です。イディオムは次のとおりです。

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

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

49
jrockway

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に読み込みます。

18
brian d foy

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

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

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

7
kixx

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

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

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

{
    open(F, "filename");
    local $/ = undef;
    $d = <F>;
}
7
user100177

別の可能な方法:

open my $fh, '<', "filename";
read $fh, my $string, -s $fh;
close $fh;
4
echo

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

$document = <FILE>; 

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

@lines = <FILE>;
print @lines;
3
Nathan

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

my $text = "";
while (my $line = <FILE>) {
    $text .= $line;
}
2
open f, "test.txt"
$file = join '', <f>

<f>-ファイルから行の配列を返します($/のデフォルト値が"\n"である場合)、join ''はこの配列を保持します。

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

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

前に説明したように、行セパレーターを再割り当てします。ただし、STDINも再割り当てされます。

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

たとえば、それを行う:

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>};

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

オープン、ストリング連結、クローズを使用して、この読み取り不能なコードを置き換えました。ただし、代わりに明示的なファイルハンドルを使用するため、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};

これにより、ファイルハンドルが適切に閉じられます。

2
jaw

つかいます

 $/ = undef;

$document = <FILE>;の前。 $/入力レコード区切り文字であり、デフォルトでは改行です。 undefに再定義することで、フィールド区切り記号がないと言っています。これは「スラープ」モードと呼ばれます。

undef $/local $/などのその他のソリューション(my $/は除く)は、$ /を再宣言し、同じ効果をもたらします。

1
Geremia

それが良い習慣かどうかはわかりませんが、これを使用していました。

($a=<F>);
0
zawy

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

#Get File Contents
sub gfc
{
    open FC, @_[0];
    join '', <FC>;
}
0
Sheldon Juncker