So-net無料ブログ作成

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

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

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。