タイトルBrowsing Mac OS X》FSRefを使ったプログラムの実際カテゴリーBrowsing Mac OS X
作成日2001/4/4 16:27:22作成者新居雅行
MDOnlineの「Browsing Mac OS X」のコーナーで、2001/3/31に“Carbonアプリケーションでロングファイルネームに対応するには”、4/3に“FSSpecをFSRefベースに移行させてロングファイル名に対応”として紹介してきた、Carbonアプリケーションをロングファイルネームに対応する手法に関する記事は今回で一通りのけじめとしたい。今回は、ファイル処理でどんなAPIを使えばいいのかを紹介しよう。もちろん、元ネタは、以下のFile Managerのリファレンスである。本来は自信をもってお届けしなければならないのだが、使いこなしたAPIではないので、もれや間違いもあるかも知れないので、御意見などは有り難くちょうだいしたいと考えている。

◇File ManAger Reference
 http://devworld.apple.com/techpubs/macosx/Carbon/Files/FileManager/File_Manager/index.html

さて、Navigation ServicesやAppleEventからFSRefとして得たファイル情報であるが、少なくともファイル名の文字列を得るということはやはり行いたいところだろう。文書ファイルのタイトルなどに表示するためである。そのためのAPIはFSGetCatalogInfoがあるのだが、このAPIではさまざまな情報を取得できる。ファイル名だけでなく、ファイルが存在するフォルダのFSRef、そしてカタログ情報だ。さらに、FSSpecまで得ることができるので、部分的にFSSpecでの処理が残っている場合もここでつなぎを取ることができる。逆に言えば、ファイル情報を得る機能はこれだけであると言ってもいいくらいだ。
FSGetCatalogInfoで得られたファイル名の情報は、UNICODEの文字列である。アルファベットも漢字も同様に2バイトを確保するタイプのUNICODE文字列だ。File ManagerのAPIはこのタイプのUNICODE文字列を使う。この文字列も構造体として記述されるが、16ビットキャラクタを1つの要素とする配列なので、配列の要素を1文字として処理できる。別のAPIにそのまま文字列を渡す場合には問題ないかもしれないが、特定の文字列を取り出したり見つけるようなプログラムの場合には注意が必要だろう。

なお、ファイルタイプやクリエイタなどの情報を得るにもFSGetCatalogInfoを使うが、ここでカタログ情報の構造体を使用する。カタログ情報の中の何の情報を取り出すかと言うことを定数で指定するなど、やや独特のやり方があるので、リファレンスをよく読んできめられた指定を行う。たとえば、ファイルタイプやクリエイタを得るには、次のように行う。

FSRef myFSRef;
FSCatalogInfoBitmap whichInfo;
FSCatalogInfo cInfo;
HFSUniStr255 outName;
FSRef parentRef;
FInfo* fInfoPtr;
OSErr er;

//myFSRefに処理対象となるファイルへの参照が設定されているとする
whichInfo = kFSCatInfoFinderInfo; //取り出す情報はFinder情報のみ
er = FSGetCatalogInfo(&myFSRef, whichInfo, &cInfo, &outName, nil, &parentRef);
fInfoPtr = (FInfo*)&(cInfo.finderInfo); //Finder情報への参照をできるようにしておく
//fInfoPtr->fdTypeでファイルタイプ得られるなど

ポイントは、FSCatalogInfoBitmap型の変数に取り出す情報の種類を定数で指定することだ。そうすると、FSCatalogInfo型構造体の指定のメンバにだけ、データが設定される。なお、FSGetCatalogInfoでは得たくない情報に関する引数にはnilを指定すればいい。前の例では、FSSpec構造体は得る必要はないので、5つ目の引数にはnilを指定した。カタログ情報の設定にはFSSetCatalogInfoを使う。

次に実際のファイルの読み書きの方法を説明しよう。やや独特の方法を使うのであるが、従来のFSSpecだとそれをもとにファイルをオープンすればよかった。Mac OS XのFile Managerでは、オープンする前に、データフォークの名称を取得し、FSRefで指定したファイルのデータフォーク名を指定して、オープンする必要がある。その意味では手順が1つ増えたことになる。ちなみに、以下のようなAPIが用意されているので、これらを使うことになる。

  • データフォーク名を得る:FSGetDataForkName
  • リソースフォーク名を得る:FSGetResourceForkName
  • フォークを開く:FSOpenFork
  • フォークを閉じる:FSCloseFork
  • ファイルからの読み込み:FSReadFork
  • ファイルへの書き込み:FSWriteFork


FSRefで指定したファイルを開いて読み出すプログラムの例は次の通りだ。まず、FSGetDataForkNameを使ってデータフォーク名を取り出しておく。ただ、実際には長さが0の文字列が取り出される。ファイルそのものの場合、フォークの名前という概念はないのかもしれない。リソースフォークをまとめて読み出すような場合などにも対応していることや、さまざまなボリューム形式でも複数のフォークに対応していることなどから、いずれにしてもこうした手続きを経る必要があるのだろう。ちなみに、HFSUniStr255型構造体は、lengthというメンバで長さ、unicodeという配列で実際の文字列を得るようになっている。そして、FSOpenForkでファイルを開く。FSRefだけでなくフォーク名を指定するが、さらにファイルのパーミッションを指定する。パーミッションは、FSSpec向けのAPIコールで使われていたのと同じ定義定数を使う。そして、ファイルへの参照値を得る。その参照値を用いて、配列などのバッファにFSReadForkデータを取り出し、最後にFSCloseForkで閉じると言うわけだ。FSReadForkでは読み出す位置の指定方法にいろいろなバリエーションがあり、やはり定義定数で指定することになる。

HFSUniStr255 dataForkName;
SInt16 forkRefNum;
Str255 a;
ByteCount cnt;
FSRef myFSRef
OSErr er;

//myFSRefに処理対象となるファイルへの参照が設定されているとする
er = FSGetDataForkName (&dataForkName);
er = FSOpenFork (&myFSRef, dataForkName.length, &dataForkName.unicode, fsRdPerm, &forkRefNum);
er = FSReadFork (forkRefNum, fsFromStart, 0, 255, &a, &cnt);
er = FSCloseFork(forkRefNum);

その他使いそうなAPIを抜粋してみた。File ManagerのAPIはあいかわらず定義の嵐だが、FSRefしか使わないということであるのなら、実際に使うAPIはごく一部だけになる。FSRef関連のAPIは他にいくつかあるが、代表的なものは、この記事で紹介できていると思う。

  • ファイルの作成:FSCreateFileUnicode
  • フォルダの作成:FSCreateDirectoryUnicode
  • ファイルやフォルダの削除:FSDeleteObject
  • ファイルやフォルダの移動:FSMoveObject
  • ファイルやフォルダの名称変更:FSRenameUnicode
  • ファイル名を指定してFSRefの作成:FSMakeFSRefUnicode
  • FSSpecからFSRefの作成:FSpMakeFSRef
  • パスからFSRefを作成:FSPathMakeRef
  • FSRefからパスを作成:FSRefMakePath

ここで、FSRefMakePathというAPIがあり、ファイルのフルパスが得られる。ただし、このフルパスは、コアOSレベルのディレクトリ階層でのフルパスだ。Finderでたどるパスとの違いがあるので注意が必要だ。また、漢字などはUTF-8でエンコードされている。つまり、ファイルシステムのキャラクタがそのままなのだ。文字列としてパスを得るためというよりも、BSDのシステムコールを呼ぶ時などに使うために用意されているのだと思われる。
ファイルを作成するFSCreateFileUnicodeでは、ファイル名などを指定するのはもちろんだが、ファイルタイプなどの付加情報はFSCatalogInfo構造体で指定する。この構造体の理解は、FSRefベースでファイル処理をするときにはとにかく欠かせないと言えるだろう。
作成しているアプリケーションをCarbon化するということで、さまざまな変更を加えてきたかもしれないが、とりあえず動いてしまうファイル関連の最適化は後回しになっていたかもしれない。一連のテキストが参考になれば幸いだ。
関連リンク