Rubyでファイルを読み取る一般的な方法は何ですか?


280

Rubyでファイルを読み取る一般的な方法は何ですか?

たとえば、次の1つの方法があります。

fileObj = File.new($fileName, "r")
while (line = fileObj.gets)
  puts(line)
end
fileObj.close

Rubyは非常に柔軟です。各アプローチの利点/欠点は何ですか?


6
現在の勝者の答えは正しいとは思いません。
歌手2014年

回答:


259
File.open("my/file/path", "r") do |f|
  f.each_line do |line|
    puts line
  end
end
# File is closed automatically at end of block

上記のようにファイルを明示的に閉じることもできます(ブロックを渡してファイルをopen閉じます):

f = File.open("my/file/path", "r")
f.each_line do |line|
  puts line
end
f.close

14
これはほとんど慣用的なRubyではありません。のforeach代わりに使用openし、each_lineブロックを省きます。
ティンマン14

7
f.each { |line| ... }そして、f.each_line { |line| ... }(少なくともRubyの2.0.0で)同じ動作を持っているようです。
chbrown、2015年

327

ファイルが長すぎない場合の最も簡単な方法は次のとおりです。

puts File.read(file_name)

確かに、IO.readまたはFile.read自動的にファイルを閉じるのでFile.open、ブロックで使用する必要はありません。


16
IO.readまたはFile.read、ファイルを自動的に閉じることもできます。
Phrogz

15
彼はすでに「ファイルが長すぎない場合」と述べました。私のケースにぴったりです。
jayP 2015年

227

「だらしない」ファイルに注意してください。これは、ファイル全体を一度にメモリに読み込むときです。

問題は、適切に拡張できないことです。適切なサイズのファイルを使用してコードを開発し、それを本番環境に配置すると、ギガバイト単位のファイルを読み取ろうとしていることがわかり、メモリを読み取って割り当てようとしているときにホストがフリーズします。

行単位のI / Oは非常に高速であり、ほとんど常に丸呑みと同じくらい効果的です。実際には驚くほど高速です。

私は使いたい:

IO.foreach("testfile") {|x| print "GOT ", x }

または

File.foreach('testfile') {|x| print "GOT", x }

ファイルはIOを継承しforeach、IO内にあるため、どちらでも使用できます。

「ファイルを「スラッピング」するのが良い習慣ではないのはなぜですか?」で、行ごとのread I / Oを介して大きなファイルを読み取ろうとすることの影響を示すいくつかのベンチマークがあります。


6
これはまさに私が探していたものです。500万行のファイルがあり、それをメモリにロードしたくありませんでした。
スコッティC.

68

あなたは一度にすべてのファイルを読むことができます:

content = File.readlines 'file.txt'
content.each_with_index{|line, i| puts "#{i+1}: #{line}"}

ファイルが大きい場合、または大きい場合は、通常、1行ずつ処理することをお勧めします。

File.foreach( 'file.txt' ) do |line|
  puts line
end

ただし、ファイルハンドルへのアクセスが必要な場合や、読み取りを自分で制御する場合があります。

File.open( 'file.txt' ) do |f|
  loop do
    break if not line = f.gets
    puts "#{f.lineno}: #{line}"
  end
end

バイナリファイルの場合は、次のようにnil-separatorとブロックサイズを指定できます。

File.open('file.bin', 'rb') do |f|
  loop do
    break if not buf = f.gets(nil, 80)
    puts buf.unpack('H*')
  end
end

最後に、たとえば複数のファイルを同時に処理する場合など、ブロックなしで実行できます。その場合、ファイルは明示的に閉じる必要があります(@antinomeのコメントに従って改善されています)。

begin
  f = File.open 'file.txt'
  while line = f.gets
    puts line
  end
ensure
  f.close
end

参考:ファイルAPIIOのAPI


2
for_eachファイルや入出力にはありません。foreach代わりに使用してください。
Tin Man

1
ここで回答で使用するコードを文書化するときは、通常、RubyMarkersプラグインと共にSublime Textエディターを使用します。IRBを使用する場合と同様に、中間結果を非常に簡単に表示できます。また、Sublime Text 2のSeeing Is Believingプラグインは本当に強力です。
Tin Man

1
すばらしい答えです。最後の例では、while代わりにloopを使用ensureして、例外が発生した場合でもファイルが確実に閉じられるようにすることをお勧めし ます。このように(セミコロンを改行で置き換えbegin; f = File.open('testfile'); while line = f.gets; puts line; end; ensure; f.close; endます):。
2015

1
ええ、それは@antinomeのほうがずっといいです。ありがとう!
Victor Klos、2015年

26

一つの簡単な方法は、使用することですreadlines

my_array = IO.readlines('filename.txt')

入力ファイルの各行は、配列のエントリになります。このメソッドは、ファイルの開閉を処理します。


5
readまたは他のバリアントと同様に、これはファイル全体をメモリにプルします。これは、ファイルが使用可能なメモリよりも大きい場合に大きな問題を引き起こす可能性があります。さらに、Rubyは配列であるため、配列を作成する必要があり、プロセスがさらに遅くなります。
ティンマン


9

私は通常これを行います:

open(path_in_string, &:read)

これにより、テキスト全体が文字列オブジェクトとして提供されます。Ruby 1.9でのみ動作します。


これは素晴らしくて短いです!ファイルも閉じますか?
mrgreenfur 2013年

5
閉じますが、スケーラブルではないので注意してください。
ティンマン

3

your_file.logまたは.txtから最後のn行を返す

path = File.join(Rails.root, 'your_folder','your_file.log')

last_100_lines = `tail -n 100 #{path}`

1

さらに効率的な方法は、オペレーティングシステムのカーネルにファイルを開いてもらい、ファイルからバイトを少しずつ読み取ってストリーミングする方法です。Rubyで1行ごとにファイルを読み取る場合、データはファイルから512バイトずつ取得され、その後「行」に分割されます。

ファイルのコンテンツをバッファリングすることにより、ファイルを論理チャンクに分割する際のI / O呼び出しの数が削減されます。

例:

このクラスをサービスオブジェクトとしてアプリに追加します。

class MyIO
  def initialize(filename)
    fd = IO.sysopen(filename)
    @io = IO.new(fd)
    @buffer = ""
  end

  def each(&block)
    @buffer << @io.sysread(512) until @buffer.include?($/)

    line, @buffer = @buffer.split($/, 2)

    block.call(line)
    each(&block)
  rescue EOFError
    @io.close
 end
end

それを呼び出して、:eachメソッドにブロックを渡します。

filename = './somewhere/large-file-4gb.txt'
MyIO.new(filename).each{|x| puts x }

詳細については、この詳細な投稿をご覧ください。

AppSignalによるRuby Magic Slurping&Streamingファイル


少なくともLinuxでは、コードが改行で終わっていない場合、そのコードは最後の行を無視します。
ヨルゲン

「@ io.close」の前に「block.call(@buffer)」を挿入すると、不足している不完全な行が取得されると思います。しかし、Rubyを使ったのはたった1日なので、間違いかもしれません。それは私のアプリケーションで機能しました:)
Jorgen

AppSignalの投稿を読んだ後、ここで小さな誤解があったようです。バッファIOを実行するその投稿からコピーしたコードは、Rubyが実際にFile.foreachまたはIO.foreach(同じメソッド)で実行することの実装例です。これらを使用する必要があり、このように再実装する必要はありません。
Peter H.Boling

@ PeterH.Bolingほとんどの場合、私はまた、再実装しないで使用する考え方をしています。しかし、ルビーは私たちが物事を開き、恥ずかしくない彼らの内面をつつくことを可能にします。それはそれがその特典の1つです。特にルビー/レールでは、実際の「すべき」または「すべきでない」というものはありません。あなたが何をしているかを知っていて、そのためのテストを書く限り。
Khalil Gharbaoui

0
content = `cat file`

この方法は、最も「珍しい」方法だと思います。多分それはちょっとトリッキーですcatが、インストールされている場合は動作します。


1
便利なトリックですが、シェルを呼び出すには多くの落とし穴があります。1)コマンドはOSによって異なる場合があります。2)ファイル名のスペースをエスケープする必要がある場合があります。あなたは、はるかに優れたルビーを使用してオフにしている組み込み関数、例えばcontent = File.read(filename)
ジェフ・ワード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.