1

私はPerlのARGVファイルハンドル(つまりwhile(<>)コンストラクト)からの入力ストリームを読み取って処理しています。通常のファイルハンドルはSTDINの場合があります。ただし、入力のかなりの部分を分析して、4つの異なるが非常に類似した形式のどれでエンコードされているかを検出する必要があります(FASTQ品質スコアの異なるASCIIエンコード。ここを参照)。データの形式を決定したら、実際にデータを読み取るために、戻ってそれらの行をもう一度解析する必要があります。

したがって、ストリームの最初の500行程度を2回読み取る必要があります。または、別の見方をすると、最初の500行を読み取ってから、もう一度読み取ることができるように「元に戻す」必要があります。私はSTDINから読んでいる可能性があるので、最初に戻ることはできません。また、ファイルは巨大であるため、すべてをメモリに読み込むことはできません(ただし、最初の500行をメモリに読み込むことは問題ありません)。これを行うための最良の方法は何ですか?

または、入力ストリームを何らかの方法で複製できますか?

編集:ちょっと待ってください。各ファイルの形式を個別に検出する必要があるため、入力を1つの大きなストリームとして処理できないことに気づきました。そのため、ARGVを使用できません。ただし、残りの質問はまだ残っています。

4

2 に答える 2

2

あなたが言ったように、ファイルハンドルがSTDINである可能性がある場合、seekそれを巻き戻すために使用することはできません。しかし、それでもかなり簡単です。私はモジュールを気にしないでしょう:

my @lines;

while (<$file>) {
  push @lines, $_;
  last if @lines == 500;
}

... # examine @lines to determine format

while (defined( $_ = @lines ? shift @lines : <$file> )) {
  ... # process line
}

一部のループdefinedに暗黙を追加する特殊なケースは、このより複雑な式には適用されないため、この場合は明示が必要であることを忘れないでください。definedwhile

于 2010-10-30T18:39:21.203 に答える
1

クラスのメソッドを提供するCPANモジュールがあります。ただし、その警告により、注意が必要になります。その適合性を慎重に評価します。unreadIO::Handle

それぞれが適度に短い500行だけを節約する必要がある場合は、そのモジュールで十分な場合があります。その例ではを使用しますSTDIN

しかし、私は魔法のARGVに神経質になっています。オペレーターが複数の個別のファイルを開いて読み取らせた場合<>、現在開いているファイルとは別のファイルにバックアップできるかどうかはわかりません。

したがって、プッシュバックロジックを自分で作成するだけになる可能性があります。それか、複数の入力ファイルやの性質に関連するARGV処理に何らかの並べ替え制限を課しますSTDIN

魔法のARGV処理を使用する私のプログラムのほとんどには、開始時に次のようなガードがあります。

if (@ARGV == 0 && -t STDIN) {
    # select one or the other of the next two lines:

    # opt 1: emit warning 
    warn "$0: reading stdin from /dev/tty\n";

    # opt 2: populate @ARGV
    @ARGV = grep { -f && -T } <*>;  # glob plain textfiles

 }

上記の2番目のケースでは、デフォルトで現在のディレクトリ内のすべてのプレーンテキストファイルになりますgrepが、空のリストが生成された場合の対処方法も決定する必要があります。

ディレクトリ引数を期待するか、少なくとも許可する一部のプログラムでは、代わりに空@ARGVを初期化することがあります"."。これにより、プログラムはデフォルトでプロセスの現在の作業ディレクトリになります。

于 2010-10-30T17:42:02.137 に答える