【问题标题】:How do I detect end of file in Ruby?如何在 Ruby 中检测文件结尾?
【发布时间】:2013-07-12 03:13:38
【问题描述】:

我编写了以下脚本来读取 CSV 文件:

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"

有了这一行,我得到了一个例外。

我想知道如何在上面的代码中检测到文件结尾。

【问题讨论】:

标签: ruby parsing csv eof


【解决方案1】:

https://www.ruby-forum.com/topic/218093#946117 谈论这个。

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

以上将整个文件“吸”到内存中。

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

您也可以使用IO#each_line。最后两个选项不会将整个文件读入内存。块的使用也使得它会自动关闭您的 IO 对象。还有其他方法,IO 和 File 类的功能非常丰富!

我指的是 IO 对象,因为 File 是 IO 的子类。当我真的不需要为对象添加 File 类中的方法时,我倾向于使用 IO。

这样你就不需要处理EOF了,Ruby会替你处理。

有时最好的处理方式是在你真的不需要的时候不这样做。

当然,Ruby 对此有 a method

【讨论】:

  • readreadlines 的问题是它们会将整个文件吞入内存,只有当您知道文件将始终放入内存时才安全。 foreach 始终是安全的,并且运行速度几乎与 slurping 整个文件相同,因此请使用 foreach,除非有很强的技术原因需要这样做,例如必须将整个文件放在一个字符串中。 each_line 是 IO 类方法 foreach 的 IO 实例版本,所以 IO.foreach 等价于 File.foreach
  • 是的,确实@theTinMan 并没有想到要提出这种区别,我认为文档中提到了它,或者我只是有意识地不再考虑它。我会在答案中加点,绝对是卖点。
  • 对于 OP 来说,理解使用 IO 和 File 方法的块形式以避免关闭文件或检查 EOF 的习惯也很重要。这只是 Ruby 让编程更加理智的另一种方式。
  • 已经完成。 :) 看起来我正在编辑它,而你正在评论它。
【解决方案2】:

试试这个简短的例子:

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

您应该在阅读完文件后关闭它。为此使用块更像 Ruby:

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 库。通常最好使用它。

【讨论】:

    【解决方案3】:

    如果不对此进行测试,您似乎应该执行救援而不是检查。

    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
    

    【讨论】:

    • 对 EOF 执行救援不一定是最好的策略,因为在文件末尾找到 eof 并不是异常行为。并且应该为异常行为保留异常,即可能不应该发生的行为,或者如果发生了,它在正常的事情流程中是不应该发生的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-04
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    相关资源
    最近更新 更多