Rubyでファイルの行を読み取る方法


237

次のコードを使用してファイルから行を読み取ろうとしました。ただし、ファイルを読み取る場合、内容はすべて1行で表示されます。

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

ただし、このファイルは各行を個別に印刷します


のようruby my_prog.rb < file.txtにstdinを使用する必要があります。この場合、ファイルが使用している行末文字を推測できません。どうすれば対応できますか?


7
するのではなく、またはline_num = 0使用することもできます。each.each_with_indexeach.with_index
Andrew Grimm、

@ andrew-grimmありがとうございます。コードがすっきりします。
抽選

を使用するよりも行ごとのIOが推奨される理由については、stackoverflow.com / q / 25189262/128421を参照してくださいread
ティンマン

line.chomp行末の処理に使用(@SreenivasanACの厚意による
Yarin

回答:


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")はすべてのケースで機能しました。
ポッド2013年

4
正しい正規表現は/\r?\n/、ポッドのコメントのように空行を組み合わせずに\ r \ nと\ nの両方をカバーする必要があります
Irongaze.com

12
これにより、ファイル全体がメモリに読み込まれますが、ファイルのサイズによっては不可能になる場合があります。
eremzeit 2013年

1
この方法は、talabesがここに答える、非常に非常に非効率的であるstackoverflow.com/a/17415655/228589が最良の答えです。これら2つの方法の実装を確認してください。
CantGetANick 2014年

1
これはルビーのやり方ではありません。以下の答えは正しい動作を示しています。
Merovex

524

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はおそらく適切に処理しています(そのため、大きなファイルによってスクリプトがクラッシュすることはありません)。
スターカーズ2013

これも使えますwith_indexか?
Joshua Pinter

1
はい、できます、例えばFile.readlines(filename).each_with_index { |line, i| puts "#{i}: #{line}" }
wulftone

この方法の方が良いようです。私は非常に大きなファイルを読み込んでいます。この方法では、ファイル全体を一度にメモリにロードしようとしてもアプリケーションがクラッシュしません。
シェルビーS

392
File.foreach(filename).with_index do |line, line_num|
   puts "#{line_num}: #{line}"
end

これにより、ファイル全体をメモリに投入せずに、ファイル内の各行に対して指定されたブロックが実行されます。参照:IO :: foreach


10
これが答えです。慣用的なRubyであり、ファイルを丸呑みしません。stackoverflow.com/a/5546681/165673
Yarin

4
ルビーの神々を称えよう!
Joshua Pinter、2015

ループ内の2行目に移動する方法は?
user1735921 2017年

18

最初のファイルにはMac Classicの行末があります(これ"\r"は通常のの代わりです"\n")。で開く

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

行末を指定します。


1
悲しいことに、少なくとも私が知っているPythonのユニバーサル改行のようなものはありません。
ジョシュリー

もう1つの質問です。rubymy_prog.rb <file.txtのように、stdinを使用する必要があります。ここで、ファイルが使用する行終了文字が何であるかを想定できません...どうすれば処理できますか?
抽選

ファイル全体をメモリにロードすることに問題がなければ、Olivierの回答が役に立ちます。ファイルのスキャン中に改行を検出すると、もう少し手間がかかります。
ジョシュリー

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

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.