superclass=Object
type=class
library=_builtin
extended=
included=Enumerable,File=Constants

基本的な入出力機能のためのクラスです。

  * [[unknown:Traps: IO ポートのオープンに関わる問題|trap::IO]]

File::Constants は、[[c:File]] から IO へ移動しました。

===[a:m17n] 多言語化と IO のエンコーディング

IO オブジェクトはエンコーディングを持ちます。
エンコーディングの影響を受けるメソッドと受けないメソッドがあります。

影響を受けるメソッドでは、IO のエンコーディングに従い読み込まれた文字列のエンコーディングが決定されます。
また IO のエンコーディングを適切に設定することにより、読み込み時・書き込み時に文字列のエンコーディングを
変換させることもできます。

==== エンコーディングの影響を受けるメソッドと受けないメソッド

IO の読み込みメソッドは2種類存在します。
テキスト読み込みメソッドとバイナリ読み込みメソッドです。

テキスト読み込みメソッドは IO のエンコーディングの影響をうけます。
詳しくは「[[ref:io_encoding]]」を参照して下さい。
以下がテキスト読み込みメソッドです。

 * [[m:IO.foreach]]
 * [[m:IO.readlines]]
 * [[m:IO#each]]
 * [[m:IO#each_line]]
 * [[m:IO#lines]]
 * [[m:IO#gets]]
 * [[m:IO#getc]]
 * [[m:IO#ungetc]]
 * [[m:IO#read]]
 * [[m:IO#readchar]]
 * [[m:IO#readline]]
 * [[m:IO#readlines]]

バイナリ読み込みメソッドは IO のエンコーディングの影響を受けません。
返す文字列のエンコーディングは常に ASCII-8BIT になります。
以下がバイナリ読み込みメソッドです。

 * [[m:IO#read]](size) 
 * [[m:IO#read_nonblock]]
 * [[m:IO#readpartial]]
 * [[m:IO#sysread]]

また書き込みメソッド [[m:IO#write]] も IO のエンコーディングの影響を受けます。
IO のすべての書き込みメソッドは内部で [[m:IO#write]] を呼びますので、
書き込みメソッドはすべて IO のエンコーディングの影響を受けます。

シーク関連のメソッドはエンコーディングの影響を受けません。
常に1バイトを単位として動作します。

例:

  f = File.open('t.txt', 'r+:euc-jp')
  p f.getc.encoding                             #=> Encoding::EUC_JP
  p f.read(1).encoding                          #=> Encoding::ASCII_8BIT 

====[a:io_encoding] IO のエンコーディングとエンコーディングの変換

IO オブジェクトは外部エンコーディングと内部エンコーディングを持ちます。
外部エンコーディングとは IO が表すファイルなどの文字エンコーディングです。
内部エンコーディングとは IO から読み込まれた文字列、あるいは IO の書き込みメソッドへ渡す文字列
の文字エンコーディングです。

以下の三通りがあります。

: IO のエンコーディングが指定されていない場合

  IO からテキスト読み込みメソッドによって読み込まれた文字列のエンコーディングは [[m:Encoding.default_external]]
  に設定されます。このとき実際の文字エンコーディングは検査されず、変換もされません。

: 外部エンコーディングのみが指定されている場合

 IO からテキスト読み込みメソッドによって読み込まれた文字列のエンコーディングは外部エンコーディング
 に設定されます。このとき実際の文字エンコーディングは検査されず、変換もされません。

 IO へ書き込まれる文字列は外部エンコーディングへと変換されます。
 外部エンコーディングへの変換方法が分からない場合は例外が発生します。

: 外部エンコーディングと内部エンコーディングが指定されている場合
 IO からテキスト読み込みメソッドによって読み込まれた文字列は外部エンコーディングから内部エンコーディングへ
 と変換されます。指定された文字エンコーディングと実際の文字エンコーディングが違っていた場合、例外が発生します。

 IO へ書き込まれる文字列は外部エンコーディングへと変換されます。
 外部エンコーディングへの変換方法が分からない場合は例外が発生します。

IO に対してエンコーディングを指定する方法には、生成時に [[m:IO.open]] や [[m:File.open]] 
に渡すモードとともに指定するものと
生成後に [[m:IO#set_encoding]] を使って指定するものの二通りがあります。詳しくはそれぞれのメソッドの項を
参照して下さい。通常は前者の方法を使います。

例1:

  f = File.open('file1')
  p f.getc.encoding        #=> Encoding::EUC_JP

例2:

  f = File.open('t.txt', 'w+:shift_jis:euc-jp')
  f.write "\xB4\xC1\xBB\xFA"            # 文字列 "漢字" の EUC-JP リテラル
  f.rewind
  s = f.read(4)
  puts s.dump                           #=> "\x8A\xBF\x8E\x9A" 
                                        # エンコーディングがSJISへ変換されていることが分かる。

===== まとめ

以上をまとめると以下の表のようになります。

読み込んだ文字列のエンコーディング

                                 指定無し          外部エンコーディングのみ    両方のエンコーディング
  ------------------------------------------------------------------------------------------------
  バイナリ読み込みメソッド      ASCII-8BIT                ASCII-8BIT                ASCII-8BIT   
                                                        
  テキスト読み込みメソッド     default_external      外部エンコーディング       内部エンコーディング    
                                                         

エンコーディングの変換

                               指定無し     外部エンコーディングのみ      両方のエンコーディング     
  ------------------------------------------------------------------------------------------------
  バイナリ読み込みメソッド     変換なし             変換なし                     変換なし               
                                                        
  テキスト読み込みメソッド     変換なし             変換なし                     変換あり                
                                                         
  書き込みメソッド             変換なし             変換あり                     変換あり               

==== ファイル名のエンコーディング

ファイル名の文字エンコーディングはプラットフォームに依存します。
ファイル名の文字エンコーディングが固定されているプラットフォーム(Win, Mac)では、
エンコーディングは暗黙に変換されます(予定)。UNIX では変換されずそのままシステムコールに渡されます。

[[m:Dir.glob]], [[m:Dir.foreach]] などが返すファイル名のエンコーディングも同様にプラットフォーム依存です。
UNIX では ASCII-8BIT です。

==== binmode

Windows の IO にはテキストモードとバイナリモードという2種類のモードが存在します。
これらのモードは上で説明した IO のエンコーディングとは独立です。改行の変換にしか影響しません。


=== EOF での読み込みメソッドの振る舞いの違い

空ファイルや EOF での各読み込みメソッドの振る舞いは以下のとおりです。
ただし、length を指定できるメソッドに関しては、length に nil または 0 を指定した場合、
EOF であっても常に空文字列 "" を返します。

//emlist{
メソッド                      空のファイルに対して

IO.read(空ファイル)           ""
IO.read(空ファイル, length)   nil
IO.readlines(空ファイル)      []
IO.foreach(空ファイル)        何もしない
//}

//emlist{
メソッド                      既にEOFだったら

IO#each                       何もしない
IO#each_byte                  何もしない
IO#getc                       nil
IO#gets                       nil
IO#read()                     ""
IO#read(length)               nil
IO#read_nonblock              EOFError
IO#readchar                   EOFError
IO#readline                   EOFError
IO#readlines                  []
IO#readpartial                EOFError
IO#sysread                    EOFError
IO#bytes                      通常どおり
IO#lines                      通常どおり
//}
