SSブログ

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"と呼んでいるようです。

参考文献

オブジェクト指向における再利用のためのデザインパターン

オブジェクト指向における再利用のためのデザインパターン

  • 作者: エリック ガンマ
  • 出版社/メーカー: ソフトバンククリエイティブ
  • 発売日: 1999/10
  • メディア: 単行本
増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門

  • 作者: 結城 浩
  • 出版社/メーカー: ソフトバンククリエイティブ
  • 発売日: 2004/06/19
  • メディア: 単行本

nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました