Help us understand the problem. What is going on with this article?

【Ruby】よく使うFileクラスを使ったファイル読み込み処理

More than 3 years have passed since last update.

Fileクラスを使ったファイルの読み込み処理のうち、個人的に良く使うパターンをテンプレコードとしてまとめた。

前提

  • ファイル読み込みでは、実際には読み込んだあとに何らかの処理をすることが多いと思うが、ここではputsで出力するだけ
  • 例外発生時は、捕捉した例外クラスとメッセージを出力するだけにする
  • カレントディレクトリにlabmen.txtという名前で以下の内容のファイルがあるものとする。
Okabe Rintaro
Shiina Mayuri
Hashida Itaru
Makise Kurisu
Kiryu Moeka
Urushibara Ruka
Feyris
Amane Suzuha

1行ずつ読み込む

IO#each_lineを使うパターン

begin
  # File.openはファイルをオープンし、Fileオブジェクトを返す
  # 第1引数: ファイルパス
  # 第2引数: ファイルモード (デフォルト => 'r')
  # 第3引数: ファイルを生成する場合のパーミッション(デフォルト => 0666)
  # 失敗した場合にErrno::EXXX例外が発生
  #
  # File.openにブロックを渡すと、
  # ブロックが終了した時点でファイルを自動でクローズする
  File.open('labmen.txt') do |file|
    # IO#each_lineは1行ずつ文字列として読み込み、それを引数にブロックを実行する
    # 第1引数: 行の区切り文字列
    # 第2引数: 最大の読み込みバイト数
    # 読み込み用にオープンされていない場合にIOError
    file.each_line do |labmen|
      # labmenには読み込んだ行が含まれる
      puts labmen
    end
  end
# 例外は小さい単位で捕捉する
rescue SystemCallError => e
  puts %Q(class=[#{e.class}] message=[#{e.message}])
rescue IOError => e
  puts %Q(class=[#{e.class}] message=[#{e.message}])
end

実行結果

Okabe Rintaro
Shiina Mayuri
Hashida Itaru
Makise Kurisu
Kiryu Moeka
Urushibara Ruka
Feyris
Amane Suzuha

IO.foreachを使うパターン

begin
  # IO.foreachはファイルの各行を引数としてブロックを繰り返し実行する
  # 第1引数: ファイルパス
  # 第2引数: 行の区切り文字 (デフォルト => $/)
  # オープンに失敗した場合、Errno::EXXX例外が発生
  File.foreach('labmen.txt') do |labmen|
    # labmenには読み込んだ行が含まれる
    puts labmen
  end
# 例外は小さい単位で捕捉する
rescue SystemCallError => e
  puts %Q(class=[#{e.class}] message=[#{e.message}])
end

実行結果

Okabe Rintaro
Shiina Mayuri
Hashida Itaru
Makise Kurisu
Kiryu Moeka
Urushibara Ruka
Feyris
Amane Suzuha

1度に全体を読み込む

IO#readを使う

begin
  File.open('labmen.txt') do |file|
    # まずIO#readでファイル全体を文字列として読み込む
    # 次にString#splitで改行文字ごとに配列に変換
    # 最後にArray#eachで要素ごとにブロックを評価
    #
    # IO#read
    # 第1引数: 読み込むサイズ(デフォルト => nil)
    # 第2引数: 出力用のバッファ(デフォルト => '')
    # 読み込み用にオープンされていない場合にIOErrorが発生
    # データの読み込みに失敗した場合にErrno::EXXXが発生
    file.read.split("\n").each do |labmen|
      puts labmen
    end
  end
# 例外は小さい単位で捕捉する
rescue SystemCallError => e
  puts %Q(class=[#{e.class}] message=[#{e.message}])
rescue IOError => e
  puts %Q(class=[#{e.class}] message=[#{e.message}])
end

実行結果

Okabe Rintaro
Shiina Mayuri
Hashida Itaru
Makise Kurisu
Kiryu Moeka
Urushibara Ruka
Feyris
Amane Suzuha

1文字ずつ読み込む

IO#each_charを使う

begin
  # File.openはファイルをオープンし、Fileオブジェクトを返す
  # 第1引数: ファイルパス
  # 第2引数: ファイルモード (デフォルト => 'r')
  # 第3引数: ファイルを生成する場合のパーミッション(デフォルト => 0666)
  # 失敗した場合にErrno::EXXX例外が発生
  #
  # File.openにブロックを渡すと、
  # ブロックが終了した時点でファイルを自動でクローズする
  File.open('labmen.txt') do |file|
    # IO#each_charは文字を1つずつブロックに渡して評価する
    # 読み込み用にオープンされていない場合にIOErrorが発生する
    file.each_char do |char|
      # 改行文字以外の場合、文字の後ろにスペースを入れて出力する
      if char != "\n"
        print "#{char} "
      else
        print char
      end
    end
  end
# 例外は小さい単位で捕捉する
rescue SystemCallError => e
  puts %Q(class=[#{e.class}] message=[#{e.message}])
rescue IOError => e
  puts %Q(class=[#{e.class}] message=[#{e.message}])
end

実行結果

O k a b e   R i n t a r o
S h i i n a   M a y u r i
H a s h i d a   I t a r u
M a k i s e   K u r i s u
K i r y u   M o e k a
U r u s h i b a r a   R u k a
F e y r i s
A m a n e   S u z u h a

ファイルロックして読み込む

File#flockを使う

begin
  # File.openはファイルをオープンし、Fileオブジェクトを返す
  # 第1引数: ファイルパス
  # 第2引数: ファイルモード (デフォルト => 'r')
  # 第3引数: ファイルを生成する場合のパーミッション(デフォルト => 0666)
  # 失敗した場合にErrno::EXXX例外が発生
  #
  # File.openにブロックを渡すと、
  # ブロックが終了した時点でファイルを自動でクローズする
  File.open('labmen.txt') do |file|
    # File#flockでファイルをロックする
    # 第1引数: ロックの種類をFile::Constantsの定数で指定(File::LOCK_EXは排他ロックを意味する)
    # 自身がcloseされている場合にIOErrorが発生
    # 引数に不正な整数を与えた場合などにErrno::EXXX例外が発生
    #
    # アンロックはファイルが閉じられるときに自動で行われる
    file.flock File::LOCK_EX

    file.each_line do |labmen|
      puts labmen
    end
  end
# 例外は小さい単位で捕捉する
rescue SystemCallError => e
  puts %Q(class=[#{e.class}] message=[#{e.message}])
rescue IOError => e
  puts %Q(class=[#{e.class}] message=[#{e.message}])
end

実行結果

Okabe Rintaro
Shiina Mayuri
Hashida Itaru
Makise Kurisu
Kiryu Moeka
Urushibara Ruka
Feyris
Amane Suzuha

ちなみに、排他ロックされたファイルを別プロセスで排他ロックしようとすると、処理が一時停止してロックが解除されたタイミングで後続の処理が走る。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした