2013-07-13 40 views
3

我寫了下面的腳本來讀取CSV文件:如何檢測Ruby中的文件結尾?

f = File.open("aFile.csv") 
text = f.read 
text.each_line do |line| 
    if (f.eof?) 
    puts "End of file reached" 
    else 
    line_num +=1 
    if(line_num < 6) then 
     puts "____SKIPPED LINE____" 
     next 
    end 
    end 

    arr = line.split(",") 
    puts "line number = #{line_num}" 
end 

此代碼運行正常,如果我拿出行:

if (f.eof?) 
    puts "End of file reached" 

這一行中我得到一個異常。

我想知道如何在上面的代碼中檢測文件的結尾。

+2

備註:文件從IO繼承; IO [有一個lineno方法](http:// ruby​​doc。info/stdlib/core/IO:lineno),不需要計數器。 – steenslag

回答

3

https://www.ruby-forum.com/topic/218093#946117談論此事。

content = File.read("file.txt") 
content = File.readlines("file.txt") 

上述'slurps'整個文件到內存中。

File.foreach("file.txt") {|line| content << line} 

您還可以使用IO#each_line。最後兩個選項不會將整個文件讀入內存。該塊的使用使得它也自動關閉你的IO對象。還有其他方法,IO和File類功能非常豐富!

我指IO對象,因爲File是IO的子類。我傾向於使用IO,當我真的不需要File對象的添加方法時。

用這種方式你不需要處理EOF,Ruby會爲你服務。

有時最好的處理方式是,當你真的不需要時。

當然,Ruby有這個a method

+1

'read'和'readlines'的問題是它們將整個文件寫入內存,只有當你知道文件將永遠適合內存時纔是安全的。 'foreach'總是安全的,並且運行速度與sl寫整個文件的速度幾乎相同,所以使用'foreach',除非有其他強有力的技術原因,例如HAVING將整個文件放在一個字符串中。 'each_line'是IO類方法'foreach'的IO實例版本,所以'IO.foreach'等價於'File.foreach'。 –

+0

是的,TheTinMan確實沒有想到要把這種區分帶出來,我認爲這是在文檔中提到的,或者我不再有意識地去思考它。我會在答案中加上一點,這絕對是一個賣點。 – vgoff

+0

對於OP來說,理解使用IO和File方法的塊形式來避免關閉文件或檢查EOF是非常重要的。這只是Ruby使編程更加理智的另一種方式。 –

1

沒有測試這個,看來你應該執行一次救援而不是檢查。

http://www.ruby-doc.org/core-2.0/EOFError.html

file = File.open("aFile.csv") 

begin 
    loop do 
    some_line = file.readline 
    # some stuff 
    end 
rescue EOFError 
    # You've reached the end. Handle it. 
end 
+0

執行EOF的救援並不一定是最好的策略,因爲在文件末尾找到'eof'並不是特別的行爲。並且例外應該保留給特殊的行爲,可能不應該發生的行爲,或者如果是這樣,那麼預期不會出現正常的事情流。 – vgoff

5

試試這個簡單的例子:

f = File.open(__FILE__) 
text = f.read 
p f.eof?  # -> true 
p text.class #-> String 

隨着f.read您閱讀整個文件轉換成文本並達到EOF。 (備註:__FILE__是腳本文件本身,你可以使用你的csv文件)。

在您的代碼中,您使用text.each_line。這對字符串文本執行each_line。它對f沒有影響。

您可以在不使用變量文本的情況下使用File#each_line。 EOF的測試不是必需的。每條線上有each_line循環,並自行檢測EOF。

f = File.open(__FILE__) 
line_num = 0 
f.each_line do |line| 
    line_num +=1 
    if (line_num < 6) 
    puts "____SKIPPED LINE____" 
    next 
    end 

    arr = line.split(",") 
    puts "line number = #{line_num}" 
end 
f.close 

您應該在閱讀後關閉文件。要使用塊,這是更紅寶石般的:

line_num = 0 
File.open(__FILE__) do | f| 
    f.each_line do |line| 
    line_num +=1 
    if (line_num < 6) 
     puts "____SKIPPED LINE____" 
     next 
    end 

    arr = line.split(",") 
    puts "line number = #{line_num}" 
    end 
end 

一個一般性的意見:有在Ruby中一個CSV庫。通常最好使用它。