4

私は現在Perlを初めて使用していますが、問題に遭遇しました:

私の仕事は、Perl で大きなファイルの行にアクセスするための簡単な方法を作成することです。可能な限り最速の方法です。500 万行からなるファイルを作成し、各行に行番号を付けました。次に、特定の行の内容を印刷できるようにする必要があるメイン プログラムを作成しました。これを行うには、インターネットで見つけた 2 つの方法を使用しています。

use Config qw( %Config );

my $off_t = $Config{lseeksize} > $Config{ivsize} ? 'F' : 'j';
my $file = "testfile.err";
open(FILE, "< $file")         or die "Can't open $file for reading: $!\n";
open(INDEX, "+>$file.idx")
        or die "Can't open $file.idx for read/write: $!\n";
build_index(*FILE, *INDEX);
my $line = line_with_index(*FILE, *INDEX, 129);
print "$line";

sub build_index {
    my $data_file  = shift;
    my $index_file = shift;
    my $offset     = 0;

    while (<$data_file>) {
        print $index_file pack($off_t, $offset);
        $offset = tell($data_file);
    }
}

sub line_with_index {
    my $data_file   = shift;
    my $index_file  = shift;
    my $line_number = shift;

    my $size;               # size of an index entry
    my $i_offset;           # offset into the index of the entry
    my $entry;              # index entry
    my $d_offset;           # offset into the data file

    $size = length(pack($off_t, 0));
    $i_offset = $size * ($line_number-1);
    seek($index_file, $i_offset, 0) or return;
    read($index_file, $entry, $size);
    $d_offset = unpack($off_t, $entry);
    seek($data_file, $d_offset, 0);
    return scalar(<$data_file>);
}

これらのメソッドは時々機能します。異なる値のセットで 10 回の試行に 1 回値を取得しますが、ほとんどの場合、「test2.pl 行 10 で文字列の初期化されていない値 $line が使用されています」(行 566 を検索するとき) が表示されますファイル) または正しい数値ではありません。さらに、インデックス作成は最初の 200 行ほどで正常に機能しているように見えますが、その後エラーが発生します。私は本当に私が間違っていることを知りません..

各行を解析する基本的なループを使用できることはわかっていますが、ファイルの 1 行を何度も再解析せずにいつでもアクセスできる方法が本当に必要です。

編集:ここにある小さなヒントを使用してみました:非常に大きなファイルで特定の行を行番号ごとに読み取る パックの「N」テンプレートを次のように置き換えました:

my $off_t = $Config{lseeksize} > $Config{ivsize} ? 'F' : 'j';

128 を取得する代わりに、空白の文字列を取得する 128 行まで、プロセスがより適切に機能します。129 の場合、3 になりますが、これはあまり意味がありません..

Edit2 :基本的に必要なのは、たとえば、既に読み取られているファイルの次の 2 行を読み取ることができるメカニズムですが、読み取りの「先頭」を現在の行 (2 行後ではありません) に保ちます。

ご協力いただきありがとうございます !

4

1 に答える 1

2

インデックス ファイルにバイナリ データを書き込むため、特に Windows を使用している場合は、ファイルハンドルをバイナリ モードに設定する必要があります。

open(INDEX, "+>$file.idx")
    or die "Can't open $file.idx for read/write: $!\n";
binmode(INDEX);

現在、Windows で次のようなことを実行すると、次のようになります。

print $index_file pack("j", $offset);

Perl は、パックされた文字列内の 0x0a を 0x0d0a に変換します。ファイルハンドルを binmode に設定すると、改行が復帰改行に変換されないようになります。

于 2014-04-16T18:04:44.637 に答える