ファイル世界との国交回復(その3)

ファイル世界との国交回復(その2) - みねこあで、FileManにちょこっと追加した #deepCopyTo: メソッドですが、そしたら梅沢さんにより本家FileManに コピー機能を追加してもらっちゃいました

追加されたのは #copyTo: メソッド。

"==ディレクトリコピー=="
'./foo' asDirectoryEntry copyTo: './bkupDir'.

"==ファイルコピー=="
'./hoge.txt' asFileEntry copyTo: './bkup/piyo.txt'

でお手軽コピーが出来るようになりました。(To:で渡すのはパス文字列・FmFileyEntry オブジェクトのどちらでもOKです)例えばこれを使って毎日バックアップ(日毎フォルダを作ってバックアップ)するなら、

'./foo' asDirectoryEntry copyTo:
           './bkup' / Date today yyyymmdd

と、ワンライナーでOK!(念のため動作を解説すると、bkupディレクトリの下の 例えば今日なら 2006-09-26 というフォルダを作って fooディレクトリの中身を全てコピー)すっごい便利です。

ファイルストリーム

せっかくなので、このコピーメソッドのコードを読んでみましょう

FmFileEntry >> copyTo: aFileEntryOrString
    | targetEntry |
    targetEntry _ aFileEntryOrString asFileEntry.
    
    FileDirectory default
        copyFile: self readStream binary
        toFile: targetEntry writeStream binary

FmFileEntry に readSteram メッセージを投げると、MultiByteFileStream オブジェクトを作って返してくれます。

'./test1.txt' asFileEntry readStream.
  "==>" MultiByteFileStream: 'C:\Squeak3.8\test1.txt'

こっから先は、FileMan に依存しない普通のファイル操作です。

MultiByteFileStream >> # binary は、ファイルの扱いを バイナリモードに切り替えます。あとはFileDirectry >> #copyFile:toFile: でコピーするだけなのです。(唯一直感的でないとしたら、インスタンスメソッドを呼ぶために適当にインスタンスを作ってる #default くらいかしら)


さて、このMultiByteFileStream とは名前の通りマルチバイトが扱えるストリームですが、これの継承関係はこんな感じです。

Object
    Stream
        PositionableStream
            WriteStream
                ReadWriteStream
                    FileStream
                        StandardFileStream
                            MultiByteFileStream

FileStreamは抽象クラスで実際の処理はMultiByteFileStream がやってくれます。例えば、FileStream の クラスメソッド #fileNamed: をブラウズするとこんなです。

fileNamed: fileName 
    ^ self concreteStream fileNamed: (self fullName: fileName)

concreteStream
    ^ MultiByteFileStream

ちなみに MultiByteFileStream は Squeak 3.8 からなのであしからず。(Squeak Nihongo7 にもあります)Squeak 3.7 では StandardFileStream が作られたそうです(伝聞:未確認)。

余談ですが、この継承木は ReadStream を継承して ReadWriteStreamを作っているのが面白いです。これはSmalltalkに多重継承がないデメリットの好例として有名のようです。(日経Linuxまつもとゆきひろ さんが Mixin の説明の時に書いていたですね)


関連記事: