ファイルの扱い方
去年の後半は全くというほど Smalltak を使っていなくって、しかも C++ 関連で覚えたことが結構ボリュームがあったので、容量の逼迫している猫の脳内では上書き保存が進行しています。
で、今になって「Smalltalk分が足りないっ!」と、Squeak でいろいろやろうとしたのですが、う・・・、アレなんだっけ、コードが出てこない orz。なんかもう、いろいろ忘れてしまったので、もう一度勉強しなおしです。
基本
ファイルの読み書きには FileStream を使用します。
"== ファイルを開いて普通に書き込む (R/W) ==" | file | file _ FileStream fileNamed: 'foobar.txt'. file nextPutAll: 'hogehogeほげほげ123'. file close
Read / Write なファイルストリームを作るには #FileNamed: メッセージを送ります。ちなみに 実際に返ってくるのは MultiByteFileStream のインスタンス などになります。 (Squeak のバージョン毎に異なるかな?)
ファイルに何かを書き込むには #nextPut: または #nextPutAll: を使います。 これは Stream に共通の操作です。
今度は読み込みます。
"== ファイルを開いて読み込む ==" file _ FileStream readOnlyFileNamed: 'foobar.txt'. Transcript cr; show: file contents. [file atEnd] whileFalse: [Transcript cr; show: ' >'; show: file next]. file reset. Transcript cr; show: ' >'; show: (file next:5). Transcript cr; show: ' >'; show: (file next:5). file close
先ほどの #FileNamed: でも構わないのですが、#readOnlyFileNamed: を使うと 書き込もうとしたときに Cannot write a read-only file と言うエラーが発生します。
内容の読み出しは #contents で全部、#next で一個づつ読み出し になります。 #atEnd と併せてループを回しながら1文字づつ読み出すことも出来ますが、 ちょっとかっこわるいコードですね。 以下、実行結果です。
hogehogeほげほげ123 >h >o >g >e >h >o >g >e >ほ >げ >ほ >げ >1 >2 >3 >hogeh >ogeほげ
文字コード
というのは、Squeak から書いて Squeak から読み込む場合。 日本語のファイルの場合、エンコードが重要になってきます。
"== Shift-JIS のファイルを書く ==" file _ FileStream fileNamed: 'foo-sjis.txt'. file converter: (TextConverter newForEncoding: 'shift-jis'). file nextPutAll: '吾輩は猫である。名前は未だ無い。'. file close. "== Shift-JIS のファイルを読む ==" file _ FileStream readOnlyFileNamed: 'foo-sjis.txt'. file converter: (TextConverter newForEncoding: 'shift-jis'). Transcript cr; cr; show: file contents. file close.
ようするに、コンバータを設定してあげれば問題なしです。
実践
FileStream は使いにくいことに いちいち close しなければいけません。 しかし、たとえちゃんと ファイル操作の末尾に close を書いたとしても 途中で例外で落ちてしまったら、やはりファイルハンドルを 握りっぱなしになってしまいます。
そこで、ファイルを扱うときは普通こうします。
"== 実践 ==" file _ FileStream readOnlyFileNamed: 'foo-sjis.txt'. [ file converter: (TextConverter newForEncoding: 'shift-jis'). Transcript cr; cr; show: file contents ] ensure: [file close]
FileMan
FileMan は 梅澤さんが作った いけてるファイル操作ライブラリです。通常操作するには以下の二つのクラスのみを知っていれば OK。
- FmFileEntry
- FmDirectoryEntry
基本的に、'パス文字列' asFileEntry とか 'パス文字列' asDirectoryEntry で この子達をつくってあげて、そこからいろいろ操作してあげる格好です。また、FmDirectoryEntry は ディレクトリを 辞書 の様に扱えるのが特徴で、#at: や #at:put: で 読み込んだり書き込んだりできます。たとえば、
'./subDir' asDirectoryEntry at: 'foo.txt' put: 'Hello, world!'
とすると、
./ └ subDir └ foo.txt #←これの中身が 'Hello, world!'
となります。
FileMan は本当に気の利いたライブラリで、
'./subDir' / 'hoge/piyo' / 'foo/var' / 'xyzzy' "print it->" C:\Squeak3.8\subDir\hoge\piyo\foo\var\xyzzy
と、 / メッセージでディレクトリの連結が出来ちゃったりします。ライブラリというよりは ファイル操作 DSL という趣が心地よいです。
・・・なぁんて、あたしのエントリを読むよりも、FileManのことはこちらを見てしまった方が早いし解りやすいです。
- FileManで楽々ファイル操作(PDF)
- ftp://swikis.ddo.jp/SqueakDevJa/events/SqueakersNight2007/FileMan.pdf
しかも
といった 直ぐに使えるサンプルコード付き!
ところで
FileMan で #at:put: で日本語を読んだり書いたりすると UTF-8 になるのですが、Windows だとやっぱり Shift-JIS で扱いたい。ちょっとだけなら
"== sjis 書き込み ==" './subDir' asDirectoryEntry binaryAt: 'bar.txt' put: ('こんにちは、世界!' convertToEncoding: #sjis) "== sjis 読み込み ==" ('./subDir' asDirectoryEntry binaryAt: 'bar.txt') asString convertFromEncoding: #sjis
みたいに binary で読み書き + 手前エンコード とか、または FileStream にしたりすればいいけれど、Shift-JISをよく使うのなら FmFileEntory/DirectoryEntory の派生版を用意しておくと便利かもです。
追記(2008-03-17)
とか書いたら、梅澤さんから「最新のFileMan はエンコード対応してますよ」とのコメント。ありがとうございます。うー、ごめんなさい。また確認不足で嘘情報を書いてしまいましたよ、あたし...orz
というわけで、最新の FileMan では
'./subDir' asDirectoryEntry at: 'bar.txt' put: 'こんにちは、世界さん' by: 'shift-jis' './subDir' asDirectoryEntry at: 'bar.txt' by: 'shift-jis' "print it==>" 'こんにちは、世界さん'
と、Shift-JIS ファイルの扱いも簡単です。