April 13, 2009

プログラミングGauche : 14章 入出力

14章 入出力

さすがに入出力は複雑だろうな、、、となんとなく身構えていたけれど、意外とすんなり頭に入った。すっきりと抽象化されていてわかりやすい。

最低限つかんでおくべきは、入力・出力のメソッド数種類と、ポートという考え方。後は必要に応じて参照すればいい。

まず、入力用メソッド。

  • (read) : 入力からS式をひとつ読み込む。
  • (read-char) : 入力から文字をひとつ読み込む。
  • (read-line) : 入力から1行を読み込む。
  • (read-byte) : 入力から1バイトを読み込む。
そして、出力用メソッド。
  • (write <obj>) : オブジェクトの外部表現を出力する。
  • (display <obj>) : オブジェクトを人が読みやすい形で出力する。
  • (print [<obj> ...]) : (複数)オブジェクトを display 形式で出力する。
  • (format <出力先> <書式> <引数> ...) : フォーマットして出力 (Cでいうprintfに近いもの)
write は外部表現(readで読み戻し可能な形式)を出力するためのメソッド、display, print, format は人が読みやすい表現の出力を行うメソッド。

これら入出力メソッドは、デフォルトでは標準入力(stdin)・標準出力(stdout)から読み書きを行う。
インタプリタから呼び出すと、↓のように動作する。

gosh> (read)
#\a
#\a
gosh> (read)
(1 2 3)
(1 2 3)

gosh> (print #\A " abc " '(1 2 3))
A abc (1 2 3)
#<undef>


入力元や出力先を抽象的に表現するのが、「ポート」。
ポートはディスプレイ、ファイル、文字列、ソケット、などに結び付けられていて、これを先の入出力メソッドに渡してやることで任意の入力元から入力/出力先へ出力することができる。

ポートを開くメソッドは、入出力の種類(ファイルか、文字列か、etc.)と入力用か出力用かの組み合わせで決まる。

  • (open-input-file <ファイルのパス>)
  • (open-output-file <ファイルのパス>)
  • (get-input-string <文字列>)
  • (get-output-string)
ポートを閉じるメソッド。
  • (close-input-port <ポート>)
  • (close-output-port <ポート>)
基本的な使い方(入力)。

$ cat foo.txt
'(a b c d)

gosh> (define in (open-input-file "foo.txt"))  ; ポートを開く
in
gosh> (read in) ; ポートから読む
'(a b c d)
gosh> (close-input-port in) ; ポートを閉じる
#<undef>
gosh> (read in) ; 閉じたポートから読もうとするとエラー
*** IO-CLOSED-ERROR: I/O attempted on closed port: #<iport(closed) foo.txt 0x813f460>

基本的な使い方(出力)。

gosh> (define out (open-output-file "foo.txt"))  ; ポートを開く
out
gosh> (write '(1 3 5) out)  ; ポートへ書き込む
#<undef>
gosh> (close-output-port out)  ; ポートを閉じる
#<undef>
gosh> (write #\a out)  ; 閉じたポートへ書き込もうとするとエラー
*** IO-CLOSED-ERROR: I/O attempted on closed port: #<oport(closed) foo.txt 0x813f1c0>

$ cat foo.txt
(1 3 5)


基本は以上、あとはプログラミングをラクにするためのメソッドの紹介になる。

「ポートを開く→メソッド実行→ポートを閉じる」という一連の流れをまとめた(抽象化した)もの。
  • (call-with-input-file <file path> <1引数の手続き>)
  • (call-with-output-file <file path> <1引数の手続き>)
  • (call-with-input-string <string> <1引数の手続き>)
  • (call-with-output-string <1引数の手続き>)
<1引数の手続き> は、入力(出力)ポートを引数にとる手続き。

「標準入出力ポートを変更→メソッド実行」をまとめたもの。
  • (with-input-from-port <入力ポート> <引数なしの手続き> <option> ...)
  • (with-output-to-port <出力ポート> <引数なしの手続き> <option> ...)
  • (with-error-to-port <エラーポート> <引数なしの手続き>)
  • (with-ports <入力ポート> <出力ポート> <エラーポート> <引数なしの手続き>)
標準入出力を変更するので、実行するメソッド内で (read) (write) などと書けば、指定したポートから(へ)入力(出力)してくれる。

さらに、
「ポートを開く→標準入出力を開いたポートへ変更→メソッド実行→ポートを閉じる」という至れり尽くせりのメソッドもあり。
  • (with-input-from-file <file path> <引数なしの手続き> <option> ...)
  • (with-output-to-file <file path> <引数なしの手続き> <option> ...)
  • (with-input-from-string <string> <引数なしの手続き>)
  • (with-output-to-string <引数なしの手続き>)

ちょっと練習。

catコマンドもどき。
;; cat.scm
(define (cat . files)
(if (null? files)
#t
(call-with-input-file (car files)
(lambda (in)
(display (port->string in))
(apply cat (cdr files))))))

gosh> (cat "a.txt" "b.txt")
aaa
bbb
#t

copyコマンドもどき。
;; copy.scm
(define (copy src dst)
(call-with-input-file src
(lambda (in)
(with-output-to-file dst
(lambda ()
(display (port->string in)))))))

gosh> (copy "a.txt" "a_cp.txt")
#
gosh> (cat "a.txt")
aaa
#t
gosh> (cat "a_cp.txt")
aaa
#t


プログラミングGauche
プログラミングGauche
クチコミを見る



mocoh at 23:33コメント(0)トラックバック(0) 

トラックバックURL

コメントする

名前
 
  絵文字
 
 
記事検索
訪問者数
  • 今日:
  • 昨日:
  • 累計:

livedoor プロフィール

mocoh

  • ライブドアブログ