こんにちは!Webコーダー・プログラマーの貝原(@touhicomu)です。
Rubyでファイルをコードで自動的に読み込んだり、書き込んだりできたら、手作業を減らせて効率的だと思いませんか?
この記事では、ファイルの読み込み・書き込み方法について
【基礎】ファイルオプションとは?
【基礎】ファイルの読み込み
【基礎】ファイルの書き込み
【基礎】ファイルの追記
【発展】ブロックを使用した書き方
【発展】文字コードを設定する方法
といった内容で解説していきます!
プログラムからファイルを操作する処理は使用頻度が高いと言えますので、しっかりと理解していきましょう!
ファイル操作の方法を、初心者にわかりやすいようにまとめてみたので、ぜひサンプルコードを自分でカスタマイズして実行し、理解を深めてみてください。
ファイルを開くには?
ファイルを扱うためにopenメソッドを用い、まずファイルを開き、扱える状態にします。
openメソッドには2つの引数があります。
第一引数にファイル名(ファイルのある場所)を必ず指定します。
第二引数には『ファイルオプション』を指定します。
file = File.open("samurai.txt", "w") # samurai.txt => ファイル名 #“w” => 書き込み file.puts("Hello, Samurai Geeks!") file.close
openメソッドのオプション
ファイルのopenメソッドの引数には、ファイル名以外にも、そのファイルをどのモードで開くかオプションを指定する必要があります。
ファイルをどのように扱うか、という目的によってこのファイルオプションは3つに大分されます。
- ファイルを読み込む(R:read)
- 書き込む(W:write)
- 元々あるデータの末尾から付け加える(A:append)
のいずれかのモードを指定します。
3つの後に 「+」をつけると、ファイルは読み書き両用で開きます。
以下ではopenメソッドのオプションについて、それぞれ解説していきます。
file open mode r(read only)
- 読み込み専用モード
- ファイルの中身を見るだけで、変更しない時に使用する
先ほど作成したrubyコードを実行してみましょう。
実行すると、カレントディレクトリのフォルダに「samurai.txt」というファイルができます。
そのファイルには「Hello, Samurai Geeks!」と書かれています。
では、実際にこのファイルの中身が本当に「Hello, Samurai Geeks!」となっているかどうかを確かめましょう。
rubyでファイル操作のコードを書いてみましょう。
この場合、ファイルの中を見るだけですから、”r”(read only)オプションを使います。
ファイルのデータをすべてコンソール上に表示するサンプルコードです。
file = File.open("samurai.txt", "r") puts file.read #コンソールにファイルに書かれた内容を表示する file.close #ファイルを閉じる
また単に読むだけなら以下のコードも同じ動作をします。省略して書けるのでおすすめです。
puts File.read('samurai.txt')
実行結果:
Hello, Samurai Geeks!
file open mode r+(read write)
- 読み込み + 書き込み
- 読み込み書き込み両方とも行いたい時に使用する
ファイルの中身を確認して、必要に応じて書き換えたり、追加したりしたい、という場合に用います。
file = File.open("samurai.txt", "r+") p file.puts file.read # ファイルを読み込み、読み込んだ内容を文末に追加する file.close #ファイルを閉じる
実行後、samurai.txtを開いてみてください。
実行した回数分だけ行が増えているのがわかりますよね。
file open mode w(write)
- 書き込み
- ファイルが存在しない場合作成する
- 存在する場合上書き
指定したファイルが存在しない場合は新規にファイルを作成します。
指定したファイルが存在する場合はすべて上書きし、もともと書かれたデータはすべて消えます。
このプログラムを実行してみてください。
元々書かれていたsamurai.txtファイルのデータはすべて消えてしまいます。
今までの内容を残し、最後尾から追加して書きたい時は”a”(append)オプションを使用します。
file = File.open('samurai.txt',"w") file.puts "Hello Samurai!" p file.puts file.size # ファイルサイズ p file.puts file.atime # 最終アクセス時刻 p file.puts file.mtime # 最終更新時刻 file.close
また、単に少し書き込むだけなら以下のコードも使用可能です。
File.write("samurai.txt","Hello Samurai!")
この場合もsamurai.txtファイルのデータはすべて消えてしまいます。
file open mode w+(read write)
- 書き込み + 読み込み
- 上記のwに加え読み込みも行いたい時に使用する
書き込みだけではなく読み込みも行いたい時に使用します。
ファイルから読み込まれた内容に処理を加えて書き込みを行いたい場合、内部でいったん処理をする場合などに使います。
以下のサンプルコードでは、書き込み用にopenしたファイルから、いったん全部の内容を読み込んでいます。
そのため、もし”w”オプションでopenしていた場合、エラーとなります。
ここでは”w+”オプションでopenしているため、エラーとはなりません。
その後、file.putsでファイルにデータを書き込んでいます。
file = File.open("samurai.txt","w+") puts file.read # wオプションの場合はエラーになります。 file.puts "Hello Samurai!" file.puts file.size # ファイルサイズ file.puts file.atime # 最終アクセス時刻 file.puts file.mtime # 最終更新時刻 file.close
以上のように、”w+”でファイルをopenすると、書き込み用にファイルをopenしますが、ファイルから読み込みもできるようになります。
file open mode a(append)
- 指定したファイルが存在する場合は末尾から追記
- ファイルが存在しない場合作成
先ほどの”r”コードサンプルのファイルオープンモードを”a”にして動かしてみましょう。
“a”モードは、「append(追加)書き込み」の意味です。
書き込んだデータは、ファイルの末尾から追加で書き込みされます。
実際のサンプルコードを見てみましょう。
file = File.open("samurai.txt", "a") file.puts "Hello Samurai!" file.puts file.size # ファイルサイズ file.puts file.atime # 最終アクセス時刻 file.puts file.mtime # 最終更新時刻 file.close #ファイルを閉じる
プログラムを実行すると、openしたファイルの末尾から追加されていることを確認してください。
なぜ、”a”モードである「追加書き込み」モードがあるかというと、通常の書き込みモード”w”では、以前のファイルの内容が削除された上で書き込まれてしまうためです。
そのため、たとえばログファイルのように、以前のログの内容を残しつつ、新規のログの内容をログファイルに追加していくなどのケースで、追加書き込みモード”a”(append)が使用されます。
file open mode a+(append write)
- データの中身に何らかの処理を加えたうえで、末尾から新たにデータを追加したい場合にこのモードを使う
“w+”に似たような、ファイルのopenモード”a+”は、基本的にファイルへの追加書き込みモードでファイルをopenします。
また、追加書き込みに加えて、読み込みも可能です。
以下のサンプルコードを見ていきましょう。
file = File.open("samurai.txt", "a+") puts file.read #コンソールに読み込まれた内容を表示する。 #オプションが”a”の場合はエラーとなる。 file.puts "Hello Samurai!" file.puts file.size # ファイルサイズ file.puts file.atime # 最終アクセス時刻 file.puts file.mtime # 最終更新時刻 file.close #ファイルを閉じる
なぜ、追加書き込みに加えて読み込みモードもついたファイルのモードオプション”a+”があるかというと、追加書き込みの際に、対象のファイルの内容を読み込めると便利だからです。
たとえば、ログファイルに追加書き込みする前に、ログのヘッダーを読み込んで状況を把握し、ログの出力形式を変えるなどの用途にも利用できます。
基本的には追加書き込むをするけれども、状況に応じて読み込みもしたい場合に”a+”オプションを指定します。
ファイルの読み込み
読み込むファイルサイズが大きい場合、あらかじめ読み込むバイトサイズを指定して読み込むこともできます。
file = open("samurai.txt") # モード省略時は "r" でオープンされます print file.read(100) #100バイト読み込む file.close
また、readメソッドでファイルをすべて読み込むこともできます。
以下のサンプルコードでは、readでテキストファイルをすべて読み込んでいます。
読み込んだテキストはsplit(“n”)で改行でテキストを分割し、行ごとに配列にして変数linesに代入しています。
最後に、配列linesのeachメソッドを使用し、eachメソッドに与えたブロックでループしています。
ループごとに1行のテキストをブロック引数lineで受け取り、「p line」で1行ごとに画面に出力しています。
[用意するファイル(sample.txt)]
this is samurai engineer's blog, to go ahead.
[サンプルコード]
file = open("sample.txt") # モード省略時は "r" でオープンされます lines = file.read().split("n") lines.each do | line | line.chomp! puts line end file.close
[実行結果]
this is samurai engineer's blog, to go ahead.
このように、openメソッドを読み込みモード”r”で読み込んだテキストも加工する方法が色々と可能です。
ファイルの書き込み
以下のサンプルコードでは、ハッシュを順次読み込み、ファイルに一行ずつ書き込みます。
まず、”samurai_name_age.txt”を書き込みモード”w”で開いています。
その後、ハッシュhをeachメソッドでループし、ハッシュのキーをブロック変数hに、ハッシュの値をブロック変数ageに読み込んでいます。
その後、openしたファイルの変数fに対して、putsメソッドでnameとageの値を書き込んでいます。
h = { "Sho" => 25, "Ryo" => 31, "Jho" => 18 } f = File.open("samurai_name_age.txt","w") h.each do |name, age| f.puts "#{name}: #{age}" end f.close
以上のように、ファイルのopenメソッドを書き込みモード”w”で開くと、putsメソッドなどでファイルに書き込むことが可能となります。
ファイルの追記
ファイルの書き込みモード”w”を使用したサンプルのモードを追加書き込みモード”a”に変えて実行してみます。
前章と同じくファイルのopenメソッドを使い、追加書き込みモード”a”でファイルを開いています。
その後、ハッシュhをeachメソッドでループしています。
eachメソッドの各ループでは、ハッシュのキーをブロック変数nameに、ハッシュの値をブロック変数ageに取得しています。
その後、ファイルの変数fに対しputsメソッドを使いnameとageを出力しています。
h = { "Sho" => 25, "Ryo" => 31, "Jho" => 18 } f = File.open("samurai_name_age.txt","a") h.each do |name, age| f.puts "#{name}: #{age}" end f.close
実行するとわかりますが、モードオプション“w” と“a”では実行した結果が異なります。
書き込みモード“w”では、常にファイルの先頭からテキストが上書きされ、前回書き込みモードで書き込んでいた内容は失われます。
追加書き込みモード”a”では、テキストの最後尾からテキストが追加されきます。
“a”の場合は、前回書き込んだ内容は失われません。
このように、同じ書き込みモードでも、”w”と”a”では違いがあります。
より詳しいコードサンプル集としては、以下を参照してください。
ブロックを使用した書き方
ブロックとは
そもそもブロックとはなんのことでしょうか?
ブロックとは、一言で言えば、「引数のかたまり」です。
以下の記事でブロックについて詳しく説明されていますので、参考にしてみてください。
closeのサンプルコード
ブロックを使用していないため必ずfileをcloseします。
proc関数を3回呼び出し、戻り値をファイルの末尾に書き込むコードです。
#インスタンス生成 proc2 = Proc.new do |s| #sが仮引数 p "Hello, #{s}!" end file = File.open("samurai.txt","a") print("start loopn") for num in 1..3 do p file.puts num, proc2.call("SAMURAI") end print("end of loopn") file.close
ブロックを使用したサンプルコード
行単位で読み込んで何らかの処理をしたい場合、each_lineで一行ずつ読み込むこともできます。
# 自動的にファイルが閉じられる file = File.open('samurai.txt') do |file| file.each_line do |line| # lineには読み込んだ行が含まれる print line end end
業務でファイル操作をする場合は必ずブロックを使用して書くようにしましょう。
ブロックで書いた場合、File.openはそのブロックを抜けたタイミングで自動的にcloseされます。
何らかの異常があり終了した場合、closeがなされていないため、メモリリークを起こす可能性もあります。
そのため、異常終了をしてしまってもブロックFile.poenを書けば異常終了し、endを抜けた段階でcloseされます。
また、一行ずつ読み込むにはforeachも使えます。
# 自動的にファイルが閉じられる File.foreach('samurai.txt') do |file| # fileには読み込んだ行が含まれる print file end
そして、一文字ずつ読み込みたい場合にはeach_charを使います。
# 自動的にファイルが閉じられる File.open('samurai.txt') do |file| file.each_char do |char| # 改行以外の場合には文字の後ろにスペースを入れる if char != "n" print "#{char} " else print char end end end
文字コードを設定する方法
また、Rubyでは文字のエンコーディングを指定してファイルの書き込み・読み込みができます。
例えば、euc-jpを指定してファイルに書き込む場合は以下のコードです。
File.open("samurai.txt", "w:euc-jp") { |file| file.puts "おこそとのほもよろを" }
これで、samurai.txtにeur-jpの文字コードで書き込まれます。
また、euc-jpのファイルを読み込む場合は以下のようにします。
File.open("samurai.txt", "r:euc-jp") do |file| file.each_line do |line| print "#{line}:#{line.encoding}" end end
いずれもw:、r:のあとに文字コードを指定しています。
もちろん、eur-jp以外の文字コードも指定できるので必要があればサンプルコードを修正して使ってください。
Rubyを独学で頑張っているけど先が見えない方のために
そんな方、実はいらっしゃるのではないでしょうか?
そんな方であれば、これから先の話は必要ないでしょう。そっとページの閉じるボタンを押しましょう。
しかし、「先が見えない」と心の底では勘付いているそこの奥さん。この先を読み進めて、一緒に課題を深堀りしていきましょう。
なぜ「先が見えない」という不安や悩みを抱えてしまうのか
さて、「一寸先は闇だ・・・」とお悩みを抱えている方に、なぜ独学でRubyを勉強しているにもかかわらず、そのような現状を抱えてしまうのか、一緒に考えていきましょう。
先が見えない現状を踏まえ、課題として考えられるものは以下のどれかに該当するでしょう。
- プログラミングの上達が見えない
- プログラミングを継続できない気がする
- プログラミングスキルを習得した姿がイメージできない
- プログラミングスキルを活かした仕事を獲得するイメージができない
これらのどれかに該当することによって、「なんとなくプログラミング学習をしている」という状態になってしまいます。
これらの要因は、三日坊主になる理論と同じなんですが、「プログラミング学習をしなきゃ」とプログラミング学習を頑張ってしまっている状態になってしまっています。
受験勉強をやった経験のある方なら頭がもげるほどに首を縦に振ってしまう方も多いのですが、「今日も5時間勉強するぞ」や「今日はこの章を終わらすぞ」というように、学習を進めることに意識が行き過ぎてしまうと、ある程度学習を継続した後に「先が見えない・・・」となってしまいます。
未来に光を当て、プログラミング学習を「成果が出るもの」にするために
先ほど、「なぜ先が見えないという悩みや不安を抱えてしまうのか」という疑問に対しての答えを示していきました。
これらの課題というのは、独学をしていれば9割の方がぶつかってしまう壁だそうで、いわば、あるあるの現象なのです。
独学をしていて、「なんか前に進めていないぞ」と感じるのはこのせいなんですね。甘く見がちですが、非常にやっかい。
これがさらにやっかいさを極めているのは、上記に挙げた課題のほとんどが、1人で解決できないものばかりだからです。
実は、これらのほとんどが経験者に助けてもらいながら解決しないと、すぐに違う方向へと流れてしまいます。
そう言い切れるのは、以前の私もそうだったからです。
エンジニアやプログラマー関連のキャリアに詳しい方や現役のエンジニアに相談しながら修正を加え、学習を実践して今があります。
という方もいるでしょう。そういう時にこそ、プログラミングスクールの無料カウンセリングを利用するのです。
という考えに辿りついてしまいますよね。結論から言うと弊社では、そういった強引な営業等を行うことはありませんので、安心して受講できます。
「プログラミング学習の先ある未来」を光で明るく照らすには、弊社の無料カウンセリングがぴったりだと断言できます。それくらい無料カウンセリングに自信を持っているのです。
さらに、無料カウンセリングには以下の3大特典もついてきます!
- 「最短1ヶ月で開発ができる学習方法」電子書籍(非売品)
- 効率的なオリジナル学習カリキュラム
- 未経験の転職(フリーランス)を可能にするキャリアサポート
上記の特典だけでも他のスクールにはないポイントだと自信を持っている無料カウンセリング特典です。
ただプログラミング学習をする毎日から、ワクワクしながらプログラミング学習できる毎日に変える体験を一度でいいのでしてみませんか?
まとめ
いかがでしたでしょうか?
この記事では、ファイルの読み込み・書き込み方法を解説しました。
学習のポイントを振り返ってみましょう!
- ファイルの読み書きモードオプションには”r”、”w”、”a”、”r+”、”w+”、”a+”がある。
- ファイルの読み込みには”r”オプションを使う。
- ファイルの書き込みには”w”オプションを使う。
- ファイルの追加書き込みには”a”オプションを使う。
- ファイルの読み書き両方を行うにはそれぞれのオプションに”+”を追加する。
- ブロックでFileをopenすると、終了時に自動的にcloseしてくれる。
- ブロックでFileをopenすると、例外発生時にも自動的にcloseしてくれる。
- ファイルをopenする際に、文字コードを指定できる。
オプションの種類と挙動の違いを理解することで、書き込み、読み込み、または追記を使い分けられます。
そして、ブロックを使用するとfile.closeが自動的に実行されること、ブロックを使わない場合はfile.closeと書かないとメモリリークなどの問題が発生することの違いは重要ですのでよく覚えおいてください。
もしファイルの読み込み・書き込み方法について忘れてしまったらこの記事を確認してくださいね!