指定階層から下のファイル名一覧を求める

「特定のファイルタイプの書類の一覧を作成」といった場合、Mac OS X 10.4以降ではSpotlightが使えるので、AppleScriptからSpotlightを呼び出して、高速に目的のファイル一覧を取得できる。Universal Binaryアプリケーション率を求めるアプリケーション「うにばーさる」で、このテクノロジーを用いて効率的にアプリケーションファイルのみを抽出している。
■うにばーさる
http://piyo.piyocast.com/products/uni_versal_v.0.31.html

だが、指定階層から下のファイルを「すべて」取得しなくてはならない場合に、Spotlightは向いていない。

そこで、バカの一つ覚えで再帰処理によってすべてのファイルパスを収集するか、Finderにentire contentsを求めさせることになる。

set aFol to choose folder
tell application "Finder"
  set eList to entire contents of aFol
end tell

前者(再帰処理)は地道かつ安全であるがトータルの処理時間が事前に分からないという欠点がある。また、ひたすら地道な処理であるがゆえに当然の帰結として処理速度は遅くなる。

後者(entire contents)は、ファイル数が適正範囲内(数百個ぐらい?)であればかなり高速だ。欠点は、ファイル数が増えた場合にFinderがどのような挙動を起こすか分からないことである(CPU負荷率グラフが100%にベタづき状態になるとか、メモリ系のエラーになるとか)。ファイルの数が増えた場合、指数関数的に処理時間を要する場合もある。再帰処理の場合には処理時間は処理ファイル数に正比例すると考えてよいが、entire contentsの場合にはそうではないのだ。

ところが、entire contentsを求める処理で、結果を「as unicode text」でcastしつつ求めるように指定すると、比べ物にならないぐらい高速に処理できる。結果自体は高速に取得できてはいるが、各要素をAppleScriptの内部形式に変換し、さらにリストに加える際に巨大なオーバーヘッドが生じているのだろう。テキストで受信すれば、それほど大仰な処理ではないようだ。

set aFol to choose folder
tell application "Finder"
  set eList to entire contents of aFol as Unicode text
end tell

ただしこの方法における問題点は、実行結果の形式にある。すべてのファイルパス名が連結されたなが〜い文字列として返ってくきてしまうのだ。普通なら「使えねーじゃん!」と叫んでしまうところだが、あまりにも速度面でメリットが大きいので、対策してみた。

といより、以前にAppleScriptでTreeVarを実装するテストを行ったときに、このあたりの対策は施してあったのだ。ちょっとした工夫で、なが〜い文字列をファイルパスごとに区切ってリスト化できている。それほど難しい処理ではない(ただし、速度低下させないためのケアは行った)。TreeVar用にカスタマイズしまくったルーチンになっていたので、パスを返す汎用ルーチンに作り変えた。

11万ファイルでも5秒以内で全パスを取得できた(@G5 Dual 2.5GHz)。2度目からはキャッシュの効果も手伝ってか1秒以内で返ってくる。

なかなか満足の行くスピードである。これを新型のMac Proで実行するとどんなもんなんであろーか。このぐらいヘビーなテストを行ってみたいものだ。

Copyright By Piyomaru Software. All Rights Reserved