web-dev-qa-db-ja.com

Perlでファイルを開いて読み取る最良の方法は何ですか?

注意してください-ファイルを開く/読み取るための「正しい」方法や、毎回ファイルを開く/読み取る方法を探しているわけではありません。私は、ほとんどの人がどのように使用しているかを知りたいだけで、同時にいくつかの新しい方法を学ぶかもしれません:)*

私のPerlプログラムで非常に一般的なコードブロックは、ファイルを開いて、それを読み書きすることです。私はこれを行うための多くの方法を見てきましたが、このタスクを実行する上での私のスタイルは、数年にわたって何度か変わりました。 best(最良の方法があれば)メソッドがこれを行うのは何だろうと思っているだけですか?

私はこのようなファイルを開くために使用しました:

my $input_file = "/path/to/my/file";
open INPUT_FILE, "<$input_file"  || die "Can't open $input_file: $!\n";

しかし、これにはエラートラップに問題があると思います。

括弧を追加すると、エラートラップが修正されるようです。

open (INPUT_FILE, "<$input_file")  || die "Can't open $input_file: $!\n";

ファイルハンドルを変数に割り当てることもできるので、上記のように「INPUT_FILE」を使用する代わりに、$ input_filehandleを使用することもできます。

ファイルを読み込む場合、ファイルが小さい場合、このようなグロビングに問題はありますか?

my @array = <INPUT_FILE>;

または

my $file_contents = join( "\n", <INPUT_FILE> );

または、次のように常にループする必要があります。

my @array;
while (<INPUT_FILE>) {
  Push(@array, $_);
}

Perlで物事を成し遂げる方法がたくさんあることは知っていますが、ファイルを開いたり読んだりするのに好ましい/標準的な方法があるのではないかと思っています。

43
BrianH

普遍的な標準はありませんが、いずれかを好む理由があります。私の好みのフォームはこれです:

open( my $input_fh, "<", $input_file ) || die "Can't open $input_file: $!";

その理由は次のとおりです。

  • すぐにエラーを報告します。 (必要な場合は、「die」を「warn」に置き換えてください。)
  • ファイルハンドルは現在参照カウントされているため、使用しない場合は自動的に閉じられます。グローバル名INPUT_FILEHANDLEを使用する場合、ファイルを手動で閉じる必要があります。そうしないと、プログラムが終了するまで開いたままになります。
  • 読み取りモードインジケータ「<」は、$ input_fileから分離されているため、読みやすくなっています。

ファイルが小さく、すべての行が必要なことがわかっている場合は、次のことをお勧めします。

my @lines = <$input_fh>;

すべての行を単一の文字列として処理する必要がある場合は、これを行うこともできます。

my $text = join('', <$input_fh>);

長いファイルの場合は、whileを使用して行を反復処理するか、readを使用します。

58
JSBձոգչ

ファイル全体を単一の文字列として使用する場合は、ファイル全体を繰り返す必要はありません。

use strict;
use warnings;
use Carp;
use English qw( -no_match_vars );
my $data = q{};
{
   local $RS = undef; # This makes it just read the whole thing,
   my $fh;
   croak "Can't open $input_file: $!\n" if not open $fh, '<', $input_file;
   $data = <$fh>;
   croak 'Some Error During Close :/ ' if not close $fh;
}

上記はperlcritic --brutal、これは「ベストプラクティス」をテストする良い方法です:)。 $input_fileはここでは未定義ですが、残りはコーシャです。

15
Kent Fredric

どこにでも「または死ぬ」ことを書かなければならないことは、私を夢中にさせます。ファイルを開くための私の好ましい方法は次のようになります。

use autodie;

open(my $image_fh, '<', $filename);

それは非常に少ないタイピングですが、進行中の注意すべき重要なことがたくさんあります:

  • autodie プラグマを使用しています。つまり、何か問題が発生した場合、Perlのすべての組み込み関数が例外をスローします。コードにor die ...を記述する必要がなくなり、わかりやすく、人間が読めるエラーメッセージが生成され、語彙の範囲があります。 CPANから入手できます。

  • 3引数バージョンのopenを使用しています。つまり、<>、または|などの文字を含む面白いファイル名があったとしても、Perlは正しいことを行います。 OSCONでの私のPerl Securityチュートリアルでは、2引数openを誤動作させるいくつかの方法を示しました。このチュートリアルのメモは、 Perl Training Australiaからの無料ダウンロード で利用できます。

  • スカラーファイルハンドルを使用しています。これは、パッケージファイルハンドルを使用している場合に発生する可能性のある、同じ名前の誰かのファイルハンドルを偶然閉じないことを意味します。また、strictがタイプミスを見つけることができ、ファイルハンドルが範囲外になると自動的にクリーンアップされることを意味します。

  • 意味のあるファイルハンドルを使用しています。この場合、画像に書き込むように見えます。

  • ファイルハンドルは_fhで終わります。通常のスカラーのように使用しているのを見ると、おそらく間違いであることがわかります。

13
pjf

ファイルが小さく、メモリ全体をメモリに読み込むことができる場合は、 File :: Slurp を使用します。非常にシンプルなAPIで完全なファイルを読み書きし、さらにすべてのエラーチェックを行うため、必要はありません。

11
Dave Rolsky

ファイルを開いて読み取る最良の方法はありません。尋ねるのは間違った質問です。ファイルには何が含まれていますか?どの時点でどのくらいのデータが必要ですか?すべてのデータが一度に必要ですか?データをどうする必要がありますか?ファイルを開いて読み取る方法を考える前に、それらを把握する必要があります。

あなたが今やっていることはあなたに問題を引き起こしていますか?そうでなければ、解決すべきより良い問題はありませんか? :)

あなたの質問のほとんどは単なる構文であり、それはすべてPerlのドキュメントで回答されています(特に( perlopentut )。また、 Perlの学習 。質問にある問題のほとんどに答えます。

幸運を、 :)

6
brian d foy

オブジェクト指向の場合、私は好きです:

use FileHandle;
...
my $handle = FileHandle->new( "< $file_to_read" );
croak( "Could not open '$file_to_read'" ) unless $handle;
...
my $line1 = <$handle>;
my $line2 = $handle->getline;
my @lines = $handle->getlines;
$handle->close;
5
Axeman

Perlでファイルを開くための最良の方法は、多くの方法があるのと同じことです。

$files_in_the_known_universe * $Perl_programmers

...しかし、だれが通常どのようにそれを行うかを見るのはまだ面白いです。丸preferredみの好ましい形式(ファイル全体を一度に読み取る)は次のとおりです。

use strict;
use warnings;

use IO::File;

my $file = shift @ARGV or die "what file?";

my $fh = IO::File->new( $file, '<' ) or die "$file: $!";
my $data = do { local $/; <$fh> };
$fh->close();

# If you didn't just run out of memory, you have:
printf "%d characters (possibly bytes)\n", length($data);

そして、行ごとに行くとき:

my $fh = IO::File->new( $file, '<' ) or die "$file: $!";
while ( my $line = <$fh> ) {
    print "Better than cat: $line";
}
$fh->close();

もちろん、講義担当者:これらは、私が毎日の仕事のために筋肉の記憶に専念したアプローチに過ぎず、あなたが解決しようとしている問題には根本的に不適切な場合があります。

5
frosty

私はかつて

open (FILEIN, "<", $inputfile) or die "...";
my @FileContents = <FILEIN>;
close FILEIN;

定型的。最近では、File::Slurp完全にメモリに保持したい小さなファイルの場合、およびTie::Fileスケーラブルにアドレスを指定したい大きなファイルや、その場で変更したいファイル。

4
Svante

これらのプログラムがあなたの生産性のためだけのものであれば、何でも機能します!必要と思われるだけのエラー処理を組み込みます。

大きい場合はファイル全体を読み取ることは長期的には最善の方法ではない可能性があるため、配列にロードするのではなく、入ってくる行を処理することをお勧めします。

The Pragmatic Programmer(Hunt&Thomas)の章の1つから得たヒントの1つは、スライシングとダイシングを行う前に、スクリプトにファイルのバックアップを保存しておくことです。

2
John

||演算子の優先順位が高いため、結果を「open」に送信する前に最初に評価されます...前述のコードでは、代わりに「or」演算子を使用してください。そうすれば、問題は発生しません。

open INPUT_FILE, "<$input_file"
  or die "Can't open $input_file: $!\n";
2
Ape-inago

ダミアン・コンウェイは次のようにしています:

$data = readline!open(!((*{!$_},$/)=\$_)) for "filename";

しかし、私はあなたにそれをお勧めしません。

1
ysth