2

我正在尝试创建一个基本的 ruby​​ 刮板,它将从 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 方法打印所有单词,包括重复的单词,但检查 any? irb上的方法没有问题..

4

1 回答 1

14

File#write 是缓冲的,您无需在写入和 File.readlines(fname) 之间刷新或关闭 tmpF,因此 readlines 在刷新之前永远不会看到输出。我没有看到任何关闭 tmpF 的调用,因此,除了文件对象最终确定时程序退出或 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 回答