IOインスタンスの読み書きモード
Kernel.#open
とIO.open
はだいたい同じ。IOインスタンスを返す。
第二引数で指定する読み書きモードについてメモ。
各種モードの違い
読み込み可能 | 書き込み可能 | 開いた時点で 内容を白紙にする |
書き込み 開始位置 |
|
---|---|---|---|---|
r | 1 | 0 | 0 | - |
r+ | 1 | 1 | 0 | 先頭 |
w | 0 | 1 | 1 | 先頭 |
w+ | 1 | 1 | 1 | 先頭 |
a | 0 | 1 | 0 | 末尾 |
a+ | 1 | 1 | 0 | 末尾 |
r
デフォルト値。
読み込み可能 | 書き込み可能 | 開いた時点で 内容を白紙にする |
書き込み 開始位置 |
|
---|---|---|---|---|
r | 1 | 0 | 0 | - |
_
# 読み込みできる(内容が残っている) > open('alphabets.txt', 'r') {|f| f.read } => "abc\n" # 書き込みできない > open('alphabets.txt', 'r') {|f| f.write('def') } IOError: not opened for writing
r+
読み込み可能 | 書き込み可能 | 開いた時点で 内容を白紙にする |
書き込み 開始位置 |
|
---|---|---|---|---|
r+ | 1 | 1 | 0 | 先頭 |
_
# 読み込み可能(内容が残っている) > open('alphabets.txt', 'r+') {|f| f.read } => "abc\n" # 書き込み可能(書き込み位置=先頭から上書きされる) > open('alphabets.txt', 'r+') {|f| f.write('de') } => 2 > open('alphabets.txt', 'r+') {|f| f.read } => "dec\n"
w
読み込み可能 | 書き込み可能 | 開いた時点で 内容を白紙にする |
書き込み 開始位置 |
|
---|---|---|---|---|
w | 0 | 1 | 1 | 先頭 |
_
# 読み込みできない > open('alphabets.txt', 'w') {|f| f.read } IOError: not opened for reading # 書き込みできる(既存の内容は開いた時点で削除されているため、白紙状態に書き込み) > open('alphabets.txt', 'w') {|f| f.write('de') } => 2 > exit % cat alphabets.txt => de%
w+
読み込み可能 | 書き込み可能 | 開いた時点で 内容を白紙にする |
書き込み 開始位置 |
|
---|---|---|---|---|
w+ | 1 | 1 | 1 | 先頭 |
_
# 読み込みも可能(ただし既存の内容は開いた時点で削除されている) > open('alphabets.txt', 'w+') {|f| f.read } => "" # 書き込みできる(既存の内容は開いた時点で削除されているため、白紙状態に書き込み) > open('alphabets.txt', 'w+') {|f| f.write('de') } => 2 > exit % cat alphabets.txt de%
a
読み込み可能 | 書き込み可能 | 開いた時点で 内容を白紙にする |
書き込み 開始位置 |
|
---|---|---|---|---|
a | 0 | 1 | 0 | 末尾 |
_
# 読み込みできない > open('alphabets.txt', 'a') {|f| f.read } IOError: not opened for reading # 書き込みできる(末尾に追記) > open('alphabets.txt', 'a') {|f| f.write('fgh') } => 3 > exit % cat alphabets.txt defgh%
a+
読み込み可能 | 書き込み可能 | 開いた時点で 内容を白紙にする |
書き込み 開始位置 |
|
---|---|---|---|---|
a+ | 1 | 1 | 0 | 末尾 |
_
# 読み込みできる > open('alphabets.txt', 'a+') {|f| f.read } => "defgh" # 書き込みできる(末尾に追記) > open('alphabets.txt', 'a+') {|f| f.write('ijk') } => 3 > exit % cat alphabets.txt defghijk%
ファイルポインタに関する考察
IO#pos
は「ファイルポインタの現在の位置」を返す。*1
確かめてみる。
open('alphabets.txt', 'r') {|f| f.read } # => "abcde\n" open('alphabets.txt', 'r+') do |f| p f.pos # => 0 p f.gets(2) # => "ab" p f.pos # => 2 f.write('x') p f.pos # => 3 end open('alphabets.txt', 'r') {|f| f.read } # => "abxde\n" open('alphabets.txt', 'a+') do |f| p f.pos # => 0 p f.gets(2) p f.pos # => 2 f.write('x') p f.pos # => 7 p f.gets # => nil end open('alphabets.txt', 'r') {|f| f.read } # => "abxde\nx"
意外だったのは、a+
でもr+
と同様にファイルポインタは先頭から始まり、読み込むにつれて進んでいくことだ。
writeしたときにr+
だと素直にその時点でのファイルポインタの位置から書き込むが、a+
だと突然posが末尾に移動したうえで書き込みをしている模様。
そして書き込みを終えたら元の位置に戻る訳ではなく、末尾のままとなる。そのため読み込むことはできなくなる。
リファレンスなどでもこの辺りの説明は見当たらなかった。 Rubyの実装をみればわかるのだろうが、まだちと難しいので宿題にしておこう。