このページは福井県立大学の田中求之が2006年1月まで運用していた Mac のサーバ運用に関する会議室 「Web Scripter's Meeting」の記録です。情報が古くなっている可能性がありますのでご注意ください。

AppleScriptでのfileとaliasの違い

発言者:平岡憲人
( Date Monday, February 01, 1999 11:39:02 )


AppleScriptで、ファイルやフォルダを参照するときに

  set MyResult to getPageTitle alias (user_F & myFolder & ":index.html")

などとするときに、alias ... とするのと、file ... とするのでは、
どう違うのでしょうか?

コマンド(メソッド)によっても、fileとしないと動かないものもあるみたい
だし・・・

また、

  Macintosh HD:temp:hogehogefile

にアクセスするとき、このtempがフォルダのエイリアスだった場合、alias...
をつかってもアクセスに失敗するような気がするのですが、解決策は
ないでしょうか?

田中求之 さんからのコメント
( Monday, February 01, 1999 17:26:49 )

プログラマ的な回答を言うと、データの型が違います(答えになっていませんね)

file "MacHD:Folder:File"

の書式で書かれるものは、FileSpecification というファイル管理のデータの形を
とります。それにたいして、エイリアス型は、Finder のエイリアスと基本的には
同じ型のデータです。ですから、いったんエイリアス型でファイルのデータを保持
しておくと、ファイルが動かされても、追跡して見つけだそうとする(Finder の
エイリアスはそうなってますよね)といった機能がある(はず)です。

で、コマンド(イベント)が、どの型のデータを受け取るかは、そのコマンドの
実装の仕方によります。AppleEvent 内部に、File .... 型とエイリアス型を変換
してくれる機能がありますので、たいていのコマンドは、どちらを渡しても
動くようになっていると思いますが、コマンドによっては、型が一致していないと
受け付けないようになっているものもあります(StuffIt なんかは、たしか
エイリアス型しか受け付けないはず)。このへんは、コマンドの辞書情報で
確認するしかありません。

>  Macintosh HD:temp:hogehogefile

>にアクセスするとき、このtempがフォルダのエイリアスだった場合、alias...
>をつかってもアクセスに失敗するような気がするのですが、解決策は
>ないでしょうか?

フルパスをもとにエイリアス型や FFSpec 型のデータを組み立てるときには、
フルパスの部分が実体をきちんと指している必要があります。

エイリアスのフォルダーの実体の情報を Finder (または osax)に問い合わせた上で
ファイルに関するデータを組み立てます。

tell application "Finder"
  set myFile to alias (((original item of file "Macintosh HD:temp:") as string) & "hogehogefile")
end tell

てなスクリプトで、hogehogefile のエイリアス型のデータが myFile におさまります。

Hideaki Iimori さんからのコメント
( Monday, February 01, 1999 21:00:43 )

 aliasについては Inside Macintoshに解説されているにも関わらず、開
発者でも正しく理解している人が殆どいないので解説を試みてみます。

 file "..."で表される File Specifierは、Volume Reference Number + 
Directory ID Number + File Nameの組み合わせで file位置を示す物で
す。
 従って HDDの Mount順が変わったり、fileが含まれる folderが変わった
り、file名が変わると fileを特定できなくなります。
 File Specifierはある一時点での file位置を示す「通用期間のごく限ら
れた data形式」です。File位置を File Specifierで保存したりするとす
ぐに fileを見失ってしまいます。(File位置を path stringで保存する某 
OSや某アプリケーションが好例(?)です。)
 ただし、File Specifierは「存在しない file」に対しても作成すること
ができますので、新たに fileを作成するような場合は File Specifierで
指定するインターフェースを使います。

 alias "..."で表されるのは alias recordという data形式です。この操
作は Alias Managerで行います。
 alias recordは file位置を示す複数の情報を含んだ「一種の file 
search key」です。unix系 OSの経験者で「alias = symbolic link」だと
言う人がよくいますが全く違います。symbolic linkと思い込んでいる内は 
aliasを理解することはできません。
 alias recordは file search keyですから、実際に fileに accessする
時は Alias Managerを使って search動作を行い File Specifierに変換し
て file accessを行います。ここでの Alias Managerの使い方によって、
条件を厳しく唯一の fileを見つけることもできますし(通常はこの使い方
です)、条件を緩くして複数の候補 fileを探すこともできます。
 Alias Managerの search動作は柔軟にできていますので、File 
Specifierと違って fileの存在する Volume / Folder位置や file名が変
わっても fileを追跡・特定することができます。File位置を保存する場合
は必ず alias recordを使う様にします。 
 ただし、File Specifierと違って alias recordは「存在しない file」
に対しては作ることができません。ある fileが存在してそれに対応する 
search keyを作る必要があるからです。

 File Specifierと alias recordは相互に変換できますので「存在しない 
fileに対して alias recordを作ろうとする」様な場合を除き、OSA Script
や AppleEventでは通常どちらでも使えます。

alias file関連の誤解

● まず誤解されているのは、Finderが作るのは alias fileであってこれ
は alias recordを含んだものですが、あくまで Finder独自の file形式だ
ということです。Finderは Alias Managerを自分の都合の良い様に使いま
すので、「Finderの alias fileでできないこと = Alias Manager (alias 
record)でできないこと」ではありません。
 Alias Managerは強力な機能を備えていますが、これを全て使うとかえっ
てユーザが混乱する場面が出てきますので、Finderは alias fileに対して
かなり限定した Alias Managerの利用を行っています。
● 相対 Pathを示す alias recordは作れない!?
 相対 Pathを示す alias recordも作れます。
 Finderは利用形態上意味が無いので相対 alias recordを含んだ alias 
fileは作りません。
● Alias Managerは違う Volume(HDD)に移動した fileは追跡できない!?
 できます。
 Finderは利用形態上あいまいさを避けるため alias fileから違う 
Volumeまでは追跡しません。

 長文失礼 (^^;;

田中求之 さんからのコメント
( Tuesday, February 02, 1999 00:01:35 )

飯森さん、丁寧な解説をありがとうございました。個人的には、非常にすっきり
しました (^_^)

前薗 健一 さんからのコメント
( Tuesday, February 02, 1999 00:50:45 )

AppleScript はほとんど使わないのですが、田中さんと飯森さんの
解説で疑問が解けました。ありがとうございます。

平岡憲人 さんからのコメント
( Tuesday, February 02, 1999 11:06:39 )

そうか、エイリアスってシンボリックリンクではなかったの
ですか。

有り難うございます。

初歩的質問ですが、

  file "MacHD:Folder:File"

という構文は、"MacHD:Folder:File"でしめされているモノを
FSSに変換しなさいという、一種の型変換構文だということ
なのですね?

田中先生のルーチンをもとに、途中にエイリアスが含まれている
かもしれないフルパスを実態を参照するフルパスに変換するルーチン
を書いてみました。

on getFullPath(org_F, user_F)
  set oldDel to AppleScript's text item delimiters
  set AppleScript's text item delimiters to ":"
  tell application "Finder"
    repeat with myPos from 1 to count (text item of user_F)
      set mytemp to (org_F & text item myPos of user_F) as string
      if myPos is not (count (text item of user_F)) then
        set mytemp to mytemp & ":"
      end if
      if kind of alias (mytemp) is "エイリアス" then
        set org_F to (original item of alias mytemp) as string
      else
        set org_F to mytemp
      end if
    end repeat
  end tell
  set AppleScript's text item delimiters to oldDel
  return org_F
end getFullPath

指定パスを org_F & user_F で表現できるとき

  org_F  エイリアスを含んでいないことが確定しているパス文字列。
      (例えば、サーバーのルートパス)
  user_F エイリアスを含んでいるかもしれないパス文字列
      (例えば、refererからゲットした、サーバーのルートからの
       相対パス)

このルーチンを呼ぶと、戻り値がエイリアスを含まないフルパス形式
の文字列になって帰ってきます。

# if kind of alias (mytemp) is "エイリアス" then
  の所に、Tanaka's OSAX の isAlias file 関数を利用しようとしました。
  しかし、fileがエイリアスの時は、ちゃんとtrueが返って
  くるものの、fileが実体の時には、エラーで落ちてしまいます。

野本夏俊 さんからのコメント
( Tuesday, February 02, 1999 14:33:21 )

すみません、便乗質問させてください。
QuarkXPressというレイアウトソフトはAppleScriptに対応していて、
get file path of image 1
というスクリプトでドキュメントに取り込まれた画像の参照をエイリアス型のデータで
返すんですが、画像が移動されていたり、改名されていると追跡することができません。
で、調べてみたんですが、エイリアスレコードには何種類かフォーマットがあるようです。

QuarkXPressが返すエイリアスレコードはフルパス以外の情報は含まれていませんが、
普通のエイリアスレコードにはアイテムやルートのID、タイプ、クリエータといった
情報も含まれているようです。(エイリアスファイルの“alis”リソースの内容と同一)

alias "AWORK1:0"をQuarkXPressに取り込んで以下のスクリプトで取得した情報を
リンクしておきますので参照してください。

tell application "QuarkXPress"
  tell document 1
    set FP to file path of image 1
    MT Hex Dump FP -----1
  end tell
end tell
set FP to alias (FP as text)
MT Hex Dump FP -----2

Inside Macintosh の「Alias Manager」を読んで見た(と言っても英語が苦手なので
ざっと眺めただけですが(^_^;;)ところエイリアスレコードを返すルーチンには
1. NewAlias
2. NewAliasMinimal
3. NewAliasMinimalFormFullPath
の3種類があるようです。
QuarkXPressのaliasは2か3で作られている(内部ではフルパスのみを保持していて 
file path を呼ばれたときにエイリアスレコードに変換して返す)
普通のエイリアスレコードは1で作られている。という解釈であっているでしょうか?


また「レコード」と言うからには数種類のクラスで構成されているのではないかと
思うのですが、エイリアスレコードを別のクラスに変換することで内容をばらして
取得することはできないでしょうか?
たとえばスタイル付きテキストを
set {ヌclass ktxtネ:TXT, ヌclass kstyネ:Kstyle} to (cast STXT to "styl")
とすることでテキスト情報とスタイル情報に分けるようなことを
エイリアスレコードにに対してもできないもんでしょうか?

なんか、解りにくい説明ですみません。

→  サンプル

Hideaki Iimori さんからのコメント
( Tuesday, February 02, 1999 21:44:43 )

》1. NewAlias
》2. NewAliasMinimal
》3. NewAliasMinimalFormFullPath
》の3種類があるようです。

 上へ行くほど search key情報が多くなりますので追跡能力も上がり
ます。

 先の解説では「存在しない fileに対しては alias recordは作れな
い」と書きましたが、実際には NewAliasMinimalFromFullpath()を使う
と存在しない fileに対する alias recordも一応作ることができます。
 しかし、これで作った alias recordは path stringしか入っていま
せんので追跡能力も最低で、作成時の pathに正確に一致する fileしか
探せません。Pathでは同じ Volume名を区別できませんので対象 fileを
誤認する恐れもあります。
 これでは aliasとして意味がありませんので AppleScriptでは存在し
ない fileに対する alias "..."は errorにしています。(Frontierで
は作れますが aliasとしては役立たずです。)

》QuarkXPressのaliasは2か3で作られている(内部ではフルパスのみを
》保持していて file path を呼ばれたときにエイリアスレコードに変
》換して返す)普通のエイリアスレコードは1で作られている。という
》解釈であっているでしょうか?

 NewAliasMinimal()で作れば file移動/file名変更しても追跡できま
すので NewAliasMinimalFromFullpath()で作られています。従って一時
的な file位置を伝達する目的では使えますが、file位置を保存する目
的では使えません。

》また「レコード」と言うからには数種類のクラスで構成されているの
》ではないかと思うのですが、エイリアスレコードを別のクラスに変換
》することで内容をばらして取得することはできないでしょうか?

 ここでの recordは構造体の意です。
 Alias recordの中身は Alias Managerの実装方法に依存する private 
dataですので、alias record内容に依存する処理は将来的な互換性があ
りません。

 Multitask環境では他のアプリケーション動作やユーザ操作で file位
置は常に動く可能性があります。MacOSでは Alias Managerによって追
跡できるため alias recordで file指定すれば確実に処理対象を得るこ
とができます。
 他の Multitask OSでは fileを指定して処理依頼をしても対象 file
が処理時点で存在することを保証する手だてがありません。このため
「File名/Directory名は変えてはダメ」「Fileを移動してはダメ」と
いうことになってしまいます。

野本夏俊 さんからのコメント
( Wednesday, February 03, 1999 10:56:03 )

ありがとうございました。
ぼくはQuarkXPressのせいでaliasにはファイル追跡能力がないもんだと
つい最近(ていうか一昨日)まで思い込んでいたんですが、これですっきり
理解することができました。(^_^)

田中求之 さんからのコメント
( Wednesday, February 03, 1999 12:13:09 )

>途中にエイリアスが含まれている
>かもしれないフルパスを実態を参照するフルパスに変換するルーチン

どこにエイリアスのフォルダーが含まれているか分からないフルパスを
オリジナルのフルパスに変換するハンドラを書いてみました。途中に
エイリアスの情報がいくつ入っていても大丈夫な「はず」です。
昼ご飯を食べながら書いたので、ちょっとごちゃごちゃしてますが (^_^;;

on getOriginalFullPath(myPath)
  set oldDEl to AppleScript's text item delimiters
  set AppleScript's text item delimiters to {":"}
  set myPath to text items of myPath
  set AppleScript's text item delimiters to oldDEl
  
  set myFullPath to ""
  
  repeat with thisPath in myPath
    set myFullPath to myFullPath & thisPath
    try
      tell application "Finder"
        set myFullPath to (original item of file myFullPath) as string
      end tell
    on error
      set myFullPath to myFullPath & ":"
    end try
  end repeat
  
  try
    info for file myFullPath
  on error
    set myFullPath to text 1 thru -2 of myFullPath
  end try
  
  return myFullPath
  
end getOriginalFullPath

平岡憲人 さんからのコメント
( Wednesday, February 03, 1999 20:55:26 )

この辺
  set AppleScript's text item delimiters to {":"}
  set myPath to text items of myPath
とか、
この辺
  try
    info for file myFullPath
  on error
    set myFullPath to text 1 thru -2 of myFullPath
  end try
とかが、それっぽいですね。

if文で判定させるのと、エラーハンドラつかってやるのと、
どっちが、速度的に早いんでしょうか。

とりあえず、CGIをつくったのはいいんだけど、遅い
(G3で反応が30秒)んですよ。

どこかに、AppleScript高速化のTipsとかってないですか?