2

HTMLソースコードから8文字以上のすべての単語を取得する基本的なルビースクレーパーを作成しようとしています。次に、単語の最初の文字に対応するファイルにこれらを保存します。シンプルですね。

    re = /\w{8,}/
    cre = /[a-z0-9]/
    a = b.html    #This grabs the html from the browser
    matchx = a.scan(re)
    matchx.each do |xx|
        word = xx.to_s.downcase.chomp
        fchar = word[0].chr

        if (fchar.match(cre)) #Not sure if I need this
            @pcount += 1
            fname = @WordsFName+fchar   #@WordsFName is a prefix
            tmpF = File.open(fname,"a+")

            #Check for duplicates, if not write to file
            exists = File.readlines(fname).any? { |li| li[word] }
            if (!exists)                    
                tmpF.write(word+"\n")
                print word 
                @wcount += 1
            end
        end

    end

Ruby はすべての単語を正常に取得し、最初の文字を取得し、必要なすべてのファイルを開きますが、書き込みに失敗します。また、 print メソッドは重複を含むすべての単語を出力しますが、いずれかを検査しますか? irbの方法は問題ありませんでした..

4

1 に答える 1

14

File#write はバッファリングされ、書き込みと File.readlines(fname) の間で tmpF をフラッシュしたり閉じたりすることは何もしないため、フラッシュされるまで readlines には出力が表示されません。tmpF で close の呼び出しが表示されないため、ファイル オブジェクトがファイナライズされたときのプログラムの終了、または tmpF が範囲外になった後の GC を除いて、書き込みデータがいつフラッシュされるかは明確ではありません。

で書き込み後に手動でフラッシュするtmpF.flushか、開いた後にそのデフォルトの動作を行うことができますtmpF.sync = true

各ファイルが大きくなるにつれて、ファイル全体を再読み取りするため、重複チェックのコストが膨らむことに注意してください。単語セットがメモリに収まる場合は、見た単語のハッシュを保持することを検討してください。メモリに格納できるよりも大きい場合は、シリアル ファイルを毎回再読み取りする代わりにキー値ストアを検討してください。

フラッシング動作を理解するためにirbで遊んでみました。OP コードの主な問題は、tmpF ファイルに明示的/暗黙的なフラッシュまたはクローズがないことです。そのため、バッファー サイズよりも小さい可能性が高い部分的な書き込みは、tmpF ファイル オブジェクトがガベージ コレクションされるか、プログラムの終了時にのみ書き込まれます。tmpF はループのたびに新しく開かれたファイル オブジェクトを割り当てられるため、以前の反復で開かれたファイルは、GC でファイナライズされたときにのみフラッシュされます。

irb(main):001:0> t=File.open('zzz','a+')
=> #<File:zzz>
irb(main):002:0> t.write '123'
=> 3
irb(main):003:0> File.readlines('zzz')
=> []
irb(main):004:0> t=File.open('zzz','a+')
=> #<File:zzz>
irb(main):005:0> t.write '456'
=> 3
irb(main):006:0> File.readlines('zzz')
=> []
irb(main):007:0> t.close
=> nil
irb(main):008:0> File.readlines('zzz')
=> ["456"]
irb(main):009:0> t=File.open('zzz','a+')
=> #<File:zzz>
irb(main):010:0> t.write '789'
=> 3
irb(main):011:0> File.readlines('zzz')
=> ["456"]
irb(main):012:0> t.flush
=> #<File:zzz>
irb(main):013:0> File.readlines('zzz')
=> ["456789"]
irb(main):014:0> GC.start
=> nil
irb(main):015:0> File.readlines('zzz')
=> ["456789123"]
于 2012-04-19T05:45:47.930 に答える