Home > Tags > read

read

AIR: テキストファイルを非同期に読み込む - openAsync()、readMultiByte()

AIR: テキストファイル読み込みの実行結果
AIRコンポーネントではローカルのファイルにアクセスすることができます。下記のコードは日本語を含むマルチバイトのテキストファイルを読み込み、画面い表示する処理を行います。

大まかな手順

  1. FileStreamのコンストラクタの引数に対象のファイルへのパスが設定されたFileインスタンスを渡す。
  2. FileStream#openAsyncで実ファイルへのパイプ接続。
  3. この時、非同期の読み込み完了/エラーを取得するためにイベントを登録しておく。
  4. 実際の文字の読み取り(どれだけ読むか、文字コードの変換など)はFileStream#readMultiByteで行う。
  5. ストリームのインスタンスには接続時にpositionプロパティ(何処読んでいるかのポインタみたいなもの)からファイル末尾までのサイズ(bytesAvailable)を取得してるので、読み込みサイズにそれを指定。
  6. FileStream#close()でストリームを閉じる

ソースコード

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
  title="テキストビュワー">
  <mx:Script>
    <![CDATA[
    import flash.filesystem.*;
    import mx.events.*;
    import mx.controls.Alert;

    private var choDir:File = File.documentsDirectory; // 開くディレクトリを指す
    private var curFile:File; // 選択されたファイル
    private var stream:FileStream;

    private function onOpenFileBut():void {
      choDir.addEventListener(Event.SELECT, onSelectFile);
      choDir.browseForOpen("開く"); // ファイル選択ダイアログの表示
    }

    // ファイルが選択されたイベント
    private function onSelectFile(e:Event):void {
      txtArea_.text = "";
      stream = new FileStream();
      curFile = e.target as File;
      stream.addEventListener(Event.COMPLETE, onCompleteReadFile);
      stream.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorReadFile);
      stream.addEventListener(ProgressEvent.PROGRESS, onProgReadFile);
      stream.openAsync(curFile, FileMode.READ); // 非同期読み込み
      curFile.removeEventListener(Event.SELECT, onSelectFile);
    }

    private function onCompleteReadFile(e:Event):void {
      try {
        // OS標準の文字コードで読み込み
        var str:String = stream.readMultiByte(stream.bytesAvailable, File.systemCharset);
        // OS標準の改行文字への変換
        var pat:RegExp = new RegExp(File.lineEnding, "g");
        str = str.replace(pat, "n");
        txtArea_.text = str; // テキストエリアに表示
        stream.removeEventListener(Event.COMPLETE, onCompleteReadFile);
        stream.removeEventListener(IOErrorEvent.IO_ERROR, onIOErrorReadFile);
        stream.removeEventListener(ProgressEvent.PROGRESS, onProgReadFile);
      } catch (err:Error) {
        progLab_.text = "IOError: " + err;
      }
      finally {
        // パイプのクローズ
        if (stream != null) {
          stream.close();
        }
      }
    }

    private function onIOErrorReadFile(e:IOErrorEvent):void {
      Alert.show("ファイルを読み込み不可", "Error", Alert.OK, this); // 第4引数には親オブジェトを渡す
      if (stream != null) {
        stream.close();
      }
    }

    private function onProgReadFile(e:ProgressEvent):void {
      progLab_.text = "Progress: " +  e.bytesLoaded + " / " + e.bytesTotal + " bytes";
    }
    ]]>
  </mx:Script>
  <mx:VBox x="0" y="0" height="100%" width="100%">
    <mx:HBox width="100%">
      <mx:Button label="ファイルを開く" id="openBut_" click="onOpenFileBut();"/>
      <mx:Label id="progLab_"/>
    </mx:HBox>
    <mx:TextArea width="100%" height="100%" id="txtArea_"/>
  </mx:VBox>

</mx:WindowedApplication>

リファレンス

人工無脳を作ってみる (1)入力文の末尾に文字列を追加

さて、最初は単純にユーザの入力文の末尾に予め定義されている文字列を付け足して応答するだけのものです。

ソースコード

package info.yukun.chatterbot;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class SimpleChatterBot {
  private String botName = "chatterbot";
  private String callStr = "なにかしゃべってよ(>_<)";
  private String[] suffixResponses = {
    "ってアレですね、わかります(^^)b",
    "ですか?わかりません(>_<)",
    "って何?日本語でおk('`)b"};

  public void go() {
    try {
      BufferedReader stdReader = new BufferedReader(new InputStreamReader(System.in));
      System.out.print("INPUT : ");
      String response;
      String input;
      while ((input = stdReader.readLine()) != null) { // ユーザの入力待ち
        if (input.equals("")) { // 入力が無かった
          response = callStr;
        } else {
          response = decorateInput(input) + getSuffixResponse();
        }
        System.out.print(botName + ": " + response);
        System.out.print("\nINPUT : ");
      }
      stdReader.close();
      System.out.println("\nPROGRAM END");
    } catch (Exception e) {
      e.getStackTrace();
      System.exit(-1); // プログラムを終了
    }
  }

  private String getSuffixResponse() {
    int rand = (int) (Math.random() * suffixResponses.length);
    return suffixResponses[rand];
  }

  private String decorateInput(String input) {
    return "「" + input + "」";
  }

  public static void main(String[] args) {
    SimpleChatterBot bot = new SimpleChatterBot();
    bot.go();
  }
}

getSuffixResponse()メソッド内で使われているMath.random()は、

static double random()
0.0 以上で、1.0 より小さい正の符号の付いた double 値を返します。

ですので、「Math.random() * 配列の長さ」 は「0~配列の長さ-1」 を意味します。

実行結果の例

INPUT : こんにちは
chatterbot: 「こんにちは」って何?日本語でおk('`)b
INPUT : え、
chatterbot: 「え、」ですか?わかりません(>_<)
INPUT : いえ、聞き返しただけです。
chatterbot: 「いえ、聞き返しただけです。」って何?日本語でおk('`)b
INPUT :
chatterbot: なにかしゃべってよ(>_<)
INPUT : 最近どうですか?
chatterbot: 「最近どうですか?」ってアレですね、わかります(^^)b
INPUT :
PROGRAM END

なんだかー、それはかとなくばかにしていますねf^^;

最初はJavaで書いていきますが、実装する機能の種類やリリースする環境によっては恐らく途中でOOをサポートする他の言語に変更するかも。

Java: ユーザからの(標準)入力を取得 - System.inとInputStreamReaderクラス

コマンドプロンプトからキーボード(標準)入力を取得するプログラムです。

肝心の標準入力を取得する手続きはSystem.inフィールドですが、これはバイトストリームでの読み込みを行うメソッドしか持たないので、InputStreamReaderクラスでラップすることでバイトストリームを文字列に変換出来るメソッドに任せます(read()メソッド)。
しかし、InputStreamReader#read()メソッドは一文字毎にしか読み込めず非効率な面があるので、最後にBufferedReaderクラスでラップすることで入力文字をバッファに格納し一行まとめて読み込めるようにします。(readLine()メソッド)。

このように、高水準のコンポーネントにSystem.inのような低水準のコンポーネントを渡して、その中で低水準メソッドを制御する手法はTemplate Methodパターンに通じるものがあるかも。The Open-Closed Principleですね。

ソースコード

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class ReadLineSample {
  public static void main(String[] args) {
    try {
      BufferedReader stdReader =
        new BufferedReader(new InputStreamReader(System.in));
      System.out.print("INPUT : ");
      String line;
      while ((line = stdReader.readLine()) != null) { // ユーザの一行入力を待つ
        if (line.equals("")) line = "<空文字>";
        System.out.print("OUTPUT: " + line);
        System.out.print("\nINPUT : ");
      }
      stdReader.close();
      System.out.println("\nPROGRAM END");
    } catch (Exception e) {
      e.getStackTrace();
      System.exit(-1); // プログラムを終了
    }
  }
}

実行結果

文字列を入力した後Enterキーを押すと入力した文字がOUTPUTされます。

INPUT : Hello World!
OUTPUT: Hello World!
INPUT : こんにちは。
OUTPUT: こんにちは。
INPUT :
OUTPUT: <空文字>
INPUT :
PROGRAM END

プログラムを終了する際は、プロンプト上でCtrl+CかCtrl+Zを押してください。それでreadLine()の戻り値はnullとなりwhileループを抜けます。ここでの注意は、単に文字を何も入力せずEnterキーだけ打つと空文字を返すことです(≠null)。

対して、C言語でこういった処理の場合は環境に合わせた改行文字も読み込こんでいます。たぶん、JavaではInputStreamReaderのreadのどこかの段階でその辺は上手く処理されているのかな?気が向いた時に確認してみようかな。

Python: ファイル読み込み時の例外の扱い例 - try、except、else、finallyブロック

ファイルのパスや名前のミス、パーミッションの権限が無い等が原因でファイルを読み込めない場合があります。そのような場合、すなわち例外が発生した際にそこで処理を中断して、発生した例外に合わせた処理ブロックにジャンプする構文が、try:~except Error:~構文です。

今回は、コマンドライン引数で英文テキストファイル名を指定し、スクリプト内でファイル内容を読み込み、単語数をカウントし出力するスクリプトを以って、オプションのelse、finallyブロックを含めた例外ブロックの扱いを確認します。
ただし、ここでの「単語」とは、1つの空白文字で区切られた文字列とします(簡単に)。

ソースコード

# -*- coding: UTF-8 -*-

import sys

script_name = sys.argv[0]
try:
    arg = sys.argv[1]
    f = open(arg, 'r')
except IndexError:
    print 'Usage: %s TEXTFILE' % script_name
except IOError:
    print '"%s" cannot be opened.' % arg
else:
    print arg, 'contains', len(f.read().split(' ')), 'words.'
    f.close()
finally:
    print 'n"%s" process end.' % script_name
    quit()
print 'Not reach this line.'

コードの説明

tryブロック

まず、例外を発生させる恐れのある行は、tryブロック内に書きます。

ここで発生しそうなのは、コマンドライン引数が格納されているリストへのアクセス部分であるsys.argv[1]です。[]演算子で存在しない要素を参照するエラー、もとい例外が発生する恐れがあります。

また、ファイルを開くopen(arg, 'r')も冒頭の理由で例外を発生させるかもしれません。

exceptブロック

exceptブロックは、tryブロックで例外が発生した場合にのみ実行されるブロックです。その為、例外が発生しない場合は実行されません。

発生する可能性のある例外のタイプ毎にexceptブロックを書けば、そのタイプ毎の例外への対処処理を書くことが出来ます。

except TYPE_AError:
    TYPE_AErrorが発生した際のとある処理...
except TYPE_BError:
    TYPE_BErrorが発生した際のとある処理...

elseブロック (オプション)

elseブロックは全てのexceptブロックの後に書きます(任意なので書かなくても構わない)。

elseブロックはtryブロックで例外が発生しなかった場合にのみ実行されるブロックです。今回は、ファイルの読み込みとクローズに使用しています。

finallyブロック (オプション)

finallyブロックはtryブロックで例外が発生するしないに関わらず実行されるブロックです(任意なので書かなくても構わない)。

実行結果

読み込むテキストファイルを以下のaLine.txtとします。
aLine.txt

Unless I set the standard where I am in any level, I'll be puzzled about what I should do from now on.

コマンドラインで適切な引数を与えた場合

$ python excp01.py aLine.txt
aLine.txt contains 22 words.

"excp01.py" process end.

存在しないファイル名を引数を与えた場合

$ python excp01.py texfile.tex
"texfile.tex" cannot be opened.

"excp01.py" process end.

コマンドライン引数を与えなかった場合

$ python excp01.py
Usage: excp01.py TEXTFILE

"excp01.py" process end.

例外オブジェクト名をpython処理系に聞いてみる

どんなメソッドや関数、演算子が、どのような例外を投げるのか予測が付かない場合があるかと思います。
そんな場合でもとりあえずスクリプトを実行してエラーを確認してみましょう。
SyntaxError: invalid syntax以外のエラーがある場合、例えば、

$ python excp01.py
Traceback (most recent call last):
  File "excp01.py", line 5, in 
    arg = sys.argv[1]
IndexError: list index out of range

のような場合は、最終行の行頭のIndexErrorが例外名となります。

何でも例外任せにしていいの?

計算量からみてあまり良いとは言えません。今プログラムのコマンドライン引数の確認を、
if len(sys.argv) != 2: ホニャララ
とすると整数の比較ですみますが、例外のキャッチに任せると、例外インスタンスを生成し送出するという、結構な計算量がかかります。ネットワーク接続やファイル読み書きなどのIOでは有効ですが、それ以外では積極的に使わないほうがいいかもしれません。

ドキュメント

Rで統計: CSVファイルの読み込み - read.csv()メソッド

読み込むCSVファイルは2007年度のセリーグの打撃成績の順位です。

参考:2007年度 セントラル・リーグ 個人打撃成績(規定打席以上)

batting2007.csv

順位,打率,安打
1,0.346,193
2,0.343,204
3,0.318,172
4,0.313,177
5,0.31,175
6,0.308,155
7,0.302,122
8,0.302,118
9,0.3,120
10,0.3,139

プロンプト

> read.csv("batting2007.csv")
   順位  打率 安打
1     1 0.346  193
2     2 0.343  204
3     3 0.318  172
4     4 0.313  177
5     5 0.310  175
6     6 0.308  155
7     7 0.302  122
8     8 0.302  118
9     9 0.300  120
10   10 0.300  139
> batting$安打
 [1] 193 204 172 177 175 155 122 118 120 139

read.csv()メソッドでCSVファイルを読み込み、そのデータフレームをbatting変数に格納しています。

実行結果を見ると、ファイル1行目のフィールド(列)名が変数名を表し、2行目以降がテーブル本体を表していることが分かります。これによって、例えば安打の列を抽出したい場合は、batting$安打と指定すればOKです。

ただ、毎回々々「batting$安打」と指定するのは億劫ですので、以下のコマンドで簡略化します。

> attach(batting)
> 安打
 [1] 193 204 172 177 175 155 122 118 120 139
>

attach()関数によってワークスペースにオブジェクトが保存され、データフレーム内の変数名のみでのアクセスが可能になります。

read.csv()メソッドのheader引数にFALSEを指定した場合

read.csv()メソッドはデフォルトでheader引数にTRUEが指定されていますが、以下のようにFALSE(必ず大文字)を指定することも出来ます。その場合の動作は以下のようになります。

> batting <- read.csv("batting2007.csv", header=FALSE)
> batting
     V1    V2   V3
1  順位  打率 安打
2     1 0.346  193
3     2 0.343  204
4     3 0.318  172
5     4 0.313  177
6     5  0.31  175
7     6 0.308  155
8     7 0.302  122
9     8 0.302  118
10    9   0.3  120
11   10   0.3  139
> batting$V3
 [1] 安打 193  204  172  177  175  155  122  118  120  139
Levels: 118 120 122 139 155 172 175 177 193 204 安打
>

ファイル1行目の列名がテーブル本体のデータセットに組み込まれていることが分かります。この場合の列へのアクセスは上の実行結果から、batting$V3と分かります。フィールド(列)名(一行目)を省略したCSVファイルを読み込みたい場合にはこのオプション引数を指定します。

Page 1 of 3123

Home > Tags > read

バックナンバー
最近のコメント
最近のトラックバック
メタ情報

Return to page top