2017-04-03 9 views
0

私はいくつかのデータを抽出する必要がある非常に大きなテキストファイルを持っています。ファイルを1行ずつ読み込んでキーワードを探します。私が探しているキーワードは、最初よりもファイルの終わりに近いことがわかっています。 私は セットFH TACキーワードを試してみました|として、私はエラーを取得しています [オープン「のtacファイル名を」]:私のファイルサイズは、私はできませんよ大きいそのようなファイルやディレクトリはありませんTCLでファイルを終わりから終わりに(逆の順序で)読み込む方法は?

:「TAC」を実行できませんでしたその行をループに格納して、それを再度反転させます。いくつかの解決策を提案してください

答えて

0

ファイルを反転するコストは実際にはかなり高いです。私が考えることができる最良の選択肢は、行頭のファイルオフセットのリストを作成し、seek;getsパターンを使用してそのリストを調べることです。

set f [open $filename] 

# Construct the list of indices 
set indices {} 
while {![eof $f]} { 
    lappend indices [tell $f] 
    gets $f 
} 

# Iterate backwards 
foreach idx [lreverse $indices] { 
    seek $f $idx 
    set line [gets $f] 

    DoStuffWithALine $line 
} 

close $f 

それがどのようにOS前でうまく動作しないように、このアプローチのコストは(あなたがインデックスのキャッシュを持っているために起こった場合でも、あなたはまだそれに問題があると思います)非自明です - ディスクデータを取得します。

1

tacそれ自体はかなり簡単なプログラムです。少なくとも、逆の順序で各行を文字通り読み上げることに決めた場合は、Tclでアルゴリズムを実装することができます。しかし、私は制約が本当に必要ではないと思います。あなたが探しているコンテンツは、逆順で行をスキャンしなければならないということではなく、最初の近くより終わり近くにいる可能性が高いと言いました。それはあなたが少し簡単に何かできることを意味します。大まかに言えば:

  1. ファイルの最後に近いオフセットを探します。
  2. 既に処理したデータにヒットするまで、行単位で行を読み込みます。
  3. ファイルの最後から少し後ろにオフセットを探します。
  4. 既に処理したデータにヒットするまで、行単位で行を読み込みます。
  5. など

あなたが実際にあなたが今処理している単一のラインよりも、メモリ内の多くのものを維持する必要はありませんし、あなたが前にファイルの末尾にデータを処理します。この方法ファイルの前のデータ。たぶん逆の順序で行を厳密に処理することでパフォーマンスを少し向上させることができますが、最初から最後までスキャンしないことで得られる利点と比べて問題はないでしょう。

ここに、このアルゴリズムを実装するサンプルコードがあります。部分線の処理を避けるために気をつけてください。

set BLOCKSIZE 16384 
set offset  [file size $filename] 
set lastOffset [file size $filename] 

set f [open $filename r] 
while { 1 } { 
    seek $f $offset 

    if { $offset > 0 } { 
     # We may have accidentally read a partial line, because we don't 
     # know where the line boundaries are. Skip to the end of whatever 
     # line we're in, and discard the content. We'll get it instead 
     # at the end of the _next_ block. 

     gets $f 
     set offset [tell $f] 
    } 

    while { [tell $f] < $lastOffset } { 
     set line [gets $f] 

     ### Do whatever you're going to do with the line here 

     puts $line 
    } 

    set lastOffset $offset 
    if { $lastOffset == 0 } { 
     # All done, we just processed the start of the file. 

     break 
    } 

    set offset [expr {$offset - $BLOCKSIZE}] 
    if { $offset < 0 } { 
     set offset 0 
    } 
} 
close $f 
関連する問題