Ruby会打开文件但不写入它?

gzz*_*zzo 2 ruby buffer file jruby

我正在尝试创建一个基本的ruby scraper,它将从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
Run Code Online (Sandbox Code Playgroud)

Ruby成功抓取所有单词,获取第一个字符,并打开所有必需的文件,但无法写入.此外,打印方法打印所有单词,包括重复,但检查任何?irb上的方法没有问题..

dbe*_*hur 13

File#write是缓冲的,你不会在你的write和File.readlines(fname)之间刷新或关闭tmpF,所以readlines在刷新之前永远不会看到输出.我没有看到任何关闭tmpF的调用,所以,当文件对象完成时,除了程序退出,或者在tmpF超出范围后的某个时间点,除了程序退出之外,还不清楚何时刷新写入数据.

您可以在写入后手动刷新tmpF.flush,或者tmpF.sync = true在打开后使用默认行为.

请注意,随着每个文件变大,重复检查的成本将会重新读取整个文件.如果单词集适合内存,考虑只保留你看过的单词的散列,如果它大于可以存储在内存中,请考虑键值存储而不是每次重读一个串行文件.

我在irb玩弄了解冲洗行为.OP代码的主要问题是tmpF文件没有显式/隐式刷新或关闭.因此,只有当tmpF File对象被垃圾收集或程序退出时才会写入可能小于缓冲区大小的部分写入.每次通过循环时,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"]
Run Code Online (Sandbox Code Playgroud)