web-dev-qa-db-ja.com

Perlでファイルを文字列にスラッピングする最良の方法は何ですか?

はい、 それを行うには複数の方法があります ですが、標準的な方法、最も効率的な方法、または最も簡潔な方法が必要です。私が知っている回答を追加し、何がトップに浸透するかを確認します。

明確にするために、問題は、ファイルの内容を文字列に読み込む方法が最適であることです。回答ごとに1つのソリューション。

47
dreeves

これはどう:

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

ETA:注 ファイルスラップのバグ#83126:エンコーディングによるセキュリティホール(UTF-8)File :: Slurper (免責事項:私が作成したもの)を使用することをお勧めします。これは、エンコーディングに関するデフォルトの方が優れているためです。

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

または Path :: Tiny

use Path::Tiny;
path($filename)->Slurp_utf8;
70
Leon Timmermans

@ARGVをローカライズするdoブロックでこれを行うのが好きなので、ひし形演算子を使用してファイルマジックを実行できます。

 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 を使用できる可能性があります。

44
brian d foy

File :: Slurp (これが最良の方法です)を書いているとき、Uri Guttmanは多くのスラッピング方法で多くの研究を行いました。彼は ここでの彼の発見 を書き留め、それらに情報File :: Slurpを組み込んだ。

35
Schwern
open(my $f, '<', $filename) or die "OPENING $filename: $!\n";
$string = do { local($/); <$f> };
close($f);
20
dreeves

考えるべきこと(特に他のソリューションと比較した場合):

  1. 字句ファイルハンドル
  2. 範囲を縮小
  3. 魔法を減らす

だから私は得る:

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

私は実際に魔法<>を使用する場合を除いて、魔法<>の大ファンではありません。それを偽装する代わりに、なぜオープンコールを直接使用しないのですか?これはそれほど多くの作業ではなく、明示的です。 (特に「-」を処理する場合の真の魔法<>は、完全にエミュレートするための作業がはるかに多くなりますが、ここではそれを使用していません。)

11
Tanktalus

文字列の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 :: MmapFile :: 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);
10
dwarring
use Path::Class;
file('/some/path')->Slurp;
8
me me
{
  open F, $filename or die "Can't read $filename: $!";
  local $/;  # enable Slurp mode, locally.
  $file = <F>;
  close F;
}
7
zigdon
use IO::All;

# read into a string (scalar context)
$contents = io($filename)->Slurp;

# read all lines an array (array context)
@lines = io($filename)->Slurp;
5
Prakash K

これは高速でも、プラットフォームに依存せず、実際に悪でもありませんが、短いです(そして、私はラリー・ウォールのコードでこれを見てきました;-):

 my $contents = `cat $file`;

子供たちは、家でそれをしないでください;-)。

5
moritz

Perl6 :: Slurp の概要を参照してください。これは信じられないほど柔軟であり、一般的にほとんど労力を費やすことなく正しいことを行います。

4
mopoke

誰もreadやsysreadについて何も言わなかったので、ここにシンプルで速い方法があります:

my $string;
{
    open my $fh, '<', $file or die "Can't open $file: $!";
    read $fh, $string, -s $file;   # or sysread
    close $fh;
}
3
Trizen

ワンライナーの場合、通常は the -0スイッチ-n)Perlがファイル全体を一度に読み取るようにします(ファイルにnullバイトが含まれていない場合):

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

バイナリファイルの場合は、-0777

Perl -n0777e 'print length' filename
3
Qtax

以下に、最も一般的な方法の比較を示します。

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

3
dreeves

それを行うための最悪の方法の候補! (コメントを参照してください。)

open(F, $filename) or die "OPENING $filename: $!\n";
@lines = <F>;
close(F);
$string = join('', @lines);
1
dreeves

特別なレコード区切り変数$/を調整します

undef $/;
open FH, '<', $filename or die "$!\n";
my $contents = <FH>;
close FH;
0
user4951120