2012-04-19 39 views
2

我正在嘗試創建一個基本的ruby scraper,它將從html源代碼中獲取8個字母或更長的單詞。然後將它們保存在與單詞的第一個字符對應的文件中。看起來很簡單吧?Ruby將打開文件但不寫入它?拉我的頭髮

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成功抓取所有單詞,獲取第一個字符,並打開所有必需的文件,但未能寫入它。此外,打印方法打印包括重複的所有單詞,但檢查任何?在irb上的方法沒有給出任何問題..

+1

您是否收到錯誤? – scaganoff 2012-04-19 02:32:36

回答

13

文件#寫入被緩衝,並且您在寫入和File.readlines(fname)之間不會刷新或關閉tmpF,因此讀取線將永遠不會看到輸出,直到它被刷新。我沒有看到任何調用在tmpF上關閉,因此,不清楚寫入數據何時會刷新,除非程序退出時文件對象已完成,或GC在tmpF超出範圍後一段時間。

您可以在寫入​​後手動刷新,或在打開後用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"]