2015-10-05 25 views

回答

3

這要求往往不夠,我想那會解釋做什麼有用的,但首先我需要這樣說:

不要試圖讀取一個大口的文件。這就是所謂的「啜泣」,除非你能保證你總能獲得明顯小於1MB的文件,否則這是一個壞主意。有關更多信息,請參閱「Why is "slurping" a file not a good practice?」。

如果我有,看起來像一個文件:

block 1 
some text 
some text 

block 2 
some text 
some text 

,我試圖正常讀取它,我會得到這樣的:

File.read('foo.txt') 
#=> "block 1\nsome text\nsome text\n\nblock 2\nsome text\nsome text\n" 

這會使我不得不把它分解分成單獨的行,試圖找到空行,然後將其分成塊。總而言之,天真的解決方案是使用正則表達式,這種正則表達式可以工作,但不是最優的。

或者我們可以嘗試:

File.readlines('foo.txt') 
#=> ["block 1\n", "some text\n", "some text\n", "\n", "block 2\n", "some text\n", "some text\n"] 

之後,還必須找到空行,並打開陣列分爲子陣列。

相反,有兩種簡單的方法來加載文件。

  1. 牢記約啜文件,如果它是一個小文件,我們可以使用以前的警告:

    File.readlines('foo.txt', "\n\n") 
    #=> ["block 1\nsome text\nsome text\n\n", "block 2\nsome text\nsome text\n"] 
    

    請注意,在第二個參數使用"\n\n"。這就是「行分隔符」,它通常被定義爲* nix類型操作系統的「\ n」和Windows的「\ r \ n」。它實際上是基於Ruby衍生的全球價值,它親切地稱爲$/$RS$INPUT_RECORD_SEPARATOR。它們記錄在English模塊中。記錄分隔符是在文本文件中用來分隔兩行的字符,或者,對於我們的目的而言,是由兩個行尾字符或換句話說,一個段落分隔的一組行。

    讀取一次,很容易清理的內容刪除尾隨線兩端:

    File.readlines('foo.txt', "\n\n").map(&:rstrip) 
    #=> ["block 1\nsome text\nsome text", "block 2\nsome text\nsome text"] 
    

    或將其分解成子陣列:可用於

    File.readlines('foo.txt', "\n\n").map{ |s| s.rstrip.split("\n") } 
    #=> [["block 1", "some text", "some text"], ["block 2", "some text", "some text"]] 
    

    所有的例子具有類似於一個段落:

    File.readlines('foo.txt', "\n\n").map(&:rstrip).each do |line| 
        # do something with line 
    end 
    

    或:

    File.readlines('foo.txt', "\n\n").map{ |s| s.rstrip.split("\n") }.each do |paragraph| 
        # do something with the sub-array `paragraph` 
    end 
    
  2. 如果它是一個大的文件,我們可以通過foreach使用Ruby的行由行IO如果文件尚未打開,或者each_line如果它是一個已打開的文件。而且,由於您閱讀了上面的鏈接,您已經知道我們爲什麼要使用逐行IO。

    File.foreach('foo.txt', "\n\n") #=> #<Enumerator: File:foreach("foo.txt", "\n\n")> 
    

    foreach返回一個枚舉,所以我們需要釘在to_a閱讀陣列,所以我們可以看到的結果,但通常我們會不會有這樣做:

    File.foreach('foo.txt', "\n\n").to_a 
    #=> ["block 1\nsome text\nsome text\n\n", "block 2\nsome text\nsome text\n"] 
    

    這很容易使用foreach像上面:

    File.foreach('foo.txt', "\n\n").map(&:rstrip) 
    #=> ["block 1\nsome text\nsome text", "block 2\nsome text\nsome text"] 
    
    File.foreach('foo.txt', "\n\n").map(&:rstrip).map{ |s| s.rstrip.split("\n") } 
    #=> [["block 1", "some text", "some text"], ["block 2", "some text", "some text"]] 
    

    注:我強烈懷疑使用map這樣會造成simil因爲Ruby在傳遞給map之前會緩存foreach的輸出。相反,我們需要做的do塊讀取裏面的每個段落的操作:

    File.foreach('foo.txt', "\n\n") do |ary| 
        ary.rstrip.split("\n").each do |line| 
        # do something with the individual line 
        end 
    end 
    

    這樣做是小命中在性能,但是,因爲我們的目標是通過段或塊來處理,這是可以接受的。

另請注意,這是一個社區Wiki,所以請編輯並作出適當的貢獻。