如何在Ruby中读取文件行


237

我试图使用以下代码从文件中读取行。但是,当读取文件时,内容全部在一行中:

line_num=0
File.open('xxx.txt').each do |line|
  print "#{line_num += 1} #{line}"
end

但是此文件分别打印每一行。


我必须使用stdin,例如ruby my_prog.rb < file.txt,在这里我无法假设文件使用的行尾字符。我该如何处理?


7
与其做line_num = 0,不如使用each.each_with_index或可能使用each.with_index
安德鲁·格林

@ andrew-grimm谢谢,它使代码更简洁。
抽奖

请参阅stackoverflow.com/q/25189262/128421,以了解为什么逐行IO优先于使用IO read
Tin Man

使用line.chomp处理行尾(礼貌@SreenivasanAC
Yarin

Answers:


150

我相信我的回答涵盖了你关于处理任何类型的线路的结局,因为这两个新的关注点"\r\n",并"\r"转换为Linux的标准"\n"解析行之前。

为了"\r"与常规一起支持EOL字符"\n",并且"\r\n"在Windows中,我将这样做:

line_num=0
text=File.open('xxx.txt').read
text.gsub!(/\r\n?/, "\n")
text.each_line do |line|
  print "#{line_num += 1} #{line}"
end

当然,这对于大文件来说可能不是一个好主意,因为这意味着将整个文件加载到内存中。


该正则表达式不适用于我。Unix格式使用\ n,Windows \ r \ n,mac使用\ n-.gsub(/(\ r | \ n)+ /,“ \ n”)适用于所有情况。
波德

4
正确的正则表达式应能/\r?\n/覆盖\ r \ n和\ n且不会像Pod的注释那样合并空行
Irongaze.com 2013年

12
这会将整个文件读入内存,这取决于文件的大小可能是不可能的。
eremzeit

1
此方法效率极低,塔拉纸回答这里是stackoverflow.com/a/17415655/228589的最佳答案。请验证这两种方法的实现。
CantGetANick 2014年

1
这不是红宝石方式。下面的答案显示了正确的行为。
Merovex 2015年

525

Ruby确实为此提供了一种方法:

File.readlines('foo').each do |line|

http://ruby-doc.org/core-1.9.3/IO.html#method-c-readlines


这个方法比@Olivier L的方法要慢。–
HelloWorld

1
@HelloWorld可能是因为它正在从内存中删除前面的每一行,并将每一行加载到内存中。可能是错误的,但是Ruby可能做得很好(这样,大文件就不会导致脚本崩溃)。
Starkers 2013年

你也可以使用with_index吗?
约书亚·品特

1
是的,您可以,例如File.readlines(filename).each_with_index { |line, i| puts "#{i}: #{line}" }
wulftone

这种方法似乎更好。我正在读取非常大的文件,因此它不会通过尝试一次将整个文件加载到内存中而使应用程序崩溃。
谢尔比S


18

您的第一个文件具有Mac Classic行尾("\r"而不是通常的"\n")。用打开

File.open('foo').each(sep="\r") do |line|

指定行尾。


1
可悲的是,没有什么比Python中的通用换行符更好,至少我知道。
李乔(Josh Lee)

还有一个问题,我必须使用stdin,例如ruby my_prog.rb <file.txt,在这里我无法假设该文件使用的以char结尾的行是什么...我该如何处理?
绘制

如果可以将整个文件加载到内存中,Olivier的答案似乎很有帮助。在仍扫描文件的同时检测换行将需要更多的工作。
李乔(Josh Lee)

7

这是因为每行的末端。在ruby中使用chomp方法删除末尾的'\ n'或'r'。

line_num=0
File.open('xxx.txt').each do |line|
  print "#{line_num += 1} #{line.chomp}"
end

2
@SreenivisanAC +1斩!
Yarin 2015年

7

对于具有标题的文件,我偏爱以下方法:

File.open(file, "r") do |fh|
    header = fh.readline
    # Process the header
    while(line = fh.gets) != nil
        #do stuff
    end
end

这使您可以与内容行不同地处理标题行。


6

怎么样得到

myFile=File.open("paths_to_file","r")
while(line=myFile.gets)
 //do stuff with line
end

4

别忘了,如果您担心读入的文件中可能包含大行,这些行可能会在运行时淹没您的RAM,那么您始终可以零碎地读取文件。请参阅“ 为什么对文件进行毁坏是不好的 ”。

File.open('file_path', 'rb') do |io|
  while chunk = io.read(16 * 1024) do
    something_with_the chunk
    # like stream it across a network
    # or write it to another file:
    # other_io.write chunk
  end
end
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.