PythonのStreamReaderとJavaのInputStreamReaderは、意味が異なる [プログラム三昧]
今日の記事は、自分のために残したメモです。 昨日の記事では、PythonでUTF-8ファイルを読み込むための工夫を書きました。 その中で、codecs.StreamReaderというクラスを見つけたのですが、どうも、クラスに見えない。 そこで、私が理解可能なJavaに戻って、StreamReaderについて考えてみました。
Javaの場合のUTF-8ファイルの読み込み
簡単な例として、UTF-8ファイルを読み込んで、コンソールに表示するプログラムを作成してみました。
package org.noritan; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.BufferedReader; import java.nio.charset.Charset; import java.io.FileNotFoundException; import java.io.IOException; public class UtfFileRead { public static void main(String argv[]) { try { FileInputStream stream = new FileInputStream(argv[0]); try { BufferedReader reader = new BufferedReader( new InputStreamReader( stream, Charset.forName("UTF-8") ) ); try { while (reader.ready()) { System.out.println(reader.readLine()); } } catch (IOException ex) { // Failed to read from the reader // Abort reading. } finally { try { reader.close(); } catch (IOException ex) { // Failed to close reader // Do nothing } } } finally { try { stream.close(); } catch (IOException ex) { // Failed to close stream // Do nothing } } } catch (FileNotFoundException ex) { // Failed to create a FileInputStream. // Do nothing } } }
実行すると、このようになります。
Z:\noritan\java>java org.noritan.UtfFileRead in-utf.txt あいうえお かきくけこ ただいま、マイクのテスト中。
大した事をやっているわけでもないのに、例外処理がわんさか出てきました。
Javaでも、InputStreamという概念とReaderという概念が存在します。 InputStreamは、ファイルから入力した生のデータです。 したがって、複数バイトにわたる文字もバイト列として入ってきます。 それに対して、Readerは、バイト列に「文字」という概念を取り入れて、「文字」を一つずつ入力することが出来ます。
このInputStreamから入ってきたバイト列を特定のエンコーディングにしたがって、「文字列」として取り入れてReaderオブジェクトとして振舞うのが、InputStreamReaderです。 InputStreamReaderオブジェクトは、引数にInputStreamオブジェクトとエンコーディングをあらわすCharsetオブジェクトを与えて生成します。
このプログラムでは、一行ごとの処理を行わせるために、さらにBufferedReaderクラスをかぶせて使っています。
Pythonの場合のUTF-8ファイルの読み込み
Pythonでも、読み込んだUTF-8ファイルをコンソールに表示するプログラムを作成してみました。
import codecs import sys utfReaderFactory = codecs.getreader('utf-8-sig') reader = utfReaderFactory(open(sys.argv[1],'r')) sjisWriterFactory = codecs.getwriter('sjis') writer = sjisWriterFactory(sys.stdout) writer.writelines(reader.readlines()) writer.close() reader.close()
実行すると、このようになります。
Z:\noritan\python>python utfFileRead.py in-utf.txt あいうえお かきくけこ ただいま、マイクのテスト中。
Javaの場合と異なり、出力にもエンコーディングを指定しています。 これは、デフォルトの状態では、"ascii"エンコーディングになっていて、表示ができなかったためです。
Pythonの場合、"codecs.getreader('utf-8-sig')"で戻ってくるのがStreamReaderです。 しかし、これはオブジェクトでは、ありません。 Pythonのマニュアルでは、"factory"と書いてあります。 簡単に言うと、「オブジェクトを返す関数」です。
Javaの場合には、関数が直接オブジェクトになることはありません。 かならず、オブジェクトのメソッドとして関数が定義されます。
ところが、Pythonの場合には、関数単体でもオブジェクトとなることができます。 そのため、"utfReaderFactory"という変数に入れた関数を呼び出して、「UTF-8ファイルを入力するReaderオブジェクトを作成する」ことができます。 このような構成の事をデザインパターンでは、"FactoryMethod"と呼ぶのですが、"utfReaderFactory"は、関数であって、メソッドではありません。 こういう場合、なんと呼ぶのでしょうか。
まとめ
Javaの場合、関数がオブジェクトになることは出来ないので、「オブジェクトを作成する関数」を直接渡すことは出来ません。 代わりに、「オブジェクトを作成するメソッドを装備したオブジェクト」を渡して、そのメソッドを呼び出すことでオブジェクトを作成します。 このような構成を"FactoryMethod"と呼んでいます。
Pythonの場合、関数をオブジェクトとして扱うことが出来るので、"Factory"と呼ばれる「オブジェクトを作成する関数」を渡して、目的のオブジェクトを作成します。 この構成の場合には、単に"Factory"と呼んでいるようです。
コメント 0