ファイルメーカーの絶対パスと相対パス

ファイルメーカー7でファイルパスを扱うときは、注意すべき点がいくつかありますのでメモしておきたいと思います。
主に Eventを送信 スクリプトステップの中でファイルパスを扱う場合の話題です。


本体ファイルの絶対パス取得

ファイルメーカーで現在実行しているファイル(以下、本体ファイルと記載)の絶対パスは

  • Get ( ファイルパス )

で簡単に取得できます。…と言いたいところですが、 実際には

  • file:/絶対パス

という表現になっています。

そこで「file:/」を除去するため、以下の3つのようにすると絶対パスが取得できます。

Substitute ( Get ( ファイルパス ) ; "file:/" ; "" )
Right ( Get ( ファイルパス ) ; Length ( Get ( ファイルパス ) ) - 6 )
Middle ( Get ( ファイルパス ) ; 7 ; Length ( Get ( ファイルパス ) ) - 6 )

これ以外の表現も可能です。使い慣れている、あるいは状況に適したものを使用すれば良いでしょう。

次が非常に重要なことです。

ウィンドウズでこのパスを用いる場合、「/」(スラッシュ)を「\」(円記号)に変換する方が良いです。元々ウインドウズはパスの区切りに「\」を使用するOSなので、「/」だとそのままの記述では動かないコマンドがあります。そこで、

  • Substitute ( 本体ファイル絶対パス ; “/” ; “\\” )

として、「\」に変換します。ファイルメーカーでは「\」がエスケープ文字になっているので、「\」を表したいときには「\\」と記述しておく必要があります。

「/」もウィンドウズでフォルダの区切りとして認識しているはずです。ただしそのままだと実際に動かないものもあり、その辺りの記述法に詳しくないので対処法を知りません。
「\」になっていれば余計なことを考えずに済むのでお勧めします。

以上をふまえると、本体ファイルの絶対パスは

Substitute ( Get ( ファイルパス ) ; [ "file:/" ; "" ] ; [ "/" ; "\\" ] )

がスマートな記述でしょうか。

フォルダパスならファイル名と拡張子も除去して

Substitute ( Get ( ファイルパス ) ; [ "file:/" ; "" ] ; [ Get ( ファイル名 ) & ".fp7" ; "" ] ; [ "/" ; "\\" ] )

という記述です。上述した絶対パスの表現方法の違いによって書き方はいろいろあります。

Right や Middle を使用するパターンも書いてあるのは、次のような計算式で式を見やすくするためです。

  • 式内で他にも Substitute を使用する場合
  • 他の関数でも [ ] の括弧を使用する場合

処理速度は変わらないでしょうから、どれを用いるかは好みの問題だと思います。

MACでは…分かりません。持っていなくて。
ただしファイルメーカーはMACからスタートしたソフトウェアのはずですから、MACは「/」のままが良いのだと思います。もしマルチプラットフォームにするなら、Get ( システムプラットフォーム ) を使うなどして「/」の処理を分けておく必要がありそうです。


オブジェクトフィールド内のファイル・画像等のパス情報について

オブジェクトフィールドには各種ファイルが挿入できますが、「ファイルの参照データのみ保存」を指定した場合はそのファイルパスが格納されます。参照データにしない場合は本体ファイル内に取り込まれますので、ファイル名だけでパスはありません。

  • GetAsText ( オブジェクトフィールド )

と指定すると内容が取得できますが、パス以外に余計な文字列が含まれるので除去します。

参照データには少なくとも本体ファイルから見た相対パス、参照データ取得時の絶対パス情報の2つが入っています。オブジェクトの種類によって異なりますが、以下のような記述です。

  • file:ファイル相対パス
  • filewin:/ファイル絶対パス
  • image:画像相対パス
  • imagewin:/画像絶対パス

ファイルなら「file」で始まりますし、画像なら「image」といった具合です。「win」の部分はMACなら「mac」になります。

注意すべきは絶対パスが「参照データ取得時」のものである点です。
オブジェクトフィールドからファイルパスを取得して Eventを送信 に使う場合、

  1. 参照オブジェクトの絶対パス
  2. 本体ファイルがあるフォルダの絶対パス+参照オブジェクトの相対パス

のどちらの方法で指定するのか、明確に使い分ける必要があります。
通常は2の方法で指定すると思いますが、オブジェクトのファイルを絶対に移動しないのであれば1の方法で問題ありません。
また、わざと1の方法にして、別のパソコンでフォルダ構造が異なると実行されないようにする使い方もできます。


オブジェクトフィールド内の絶対パスの取得方法

前項の方法1に使う、オブジェクトの絶対パスの取得方法です。

Right ( GetAsText ( オブジェクト ) ;
  Length ( GetAsText ( オブジェクト ) ) - Position ( GetAsText ( オブジェクト ) ; "win:/" ; 1 ; 1 ) - 4
)

絶対パスは最後の行に書かれていますので「win:/」という絶対パスの文字列を検出して、以下の文字数を Right で抽出しています。

  • 全体長 – win:/の先頭文字位置 + 1 – 5(win:/の文字数)

Substituteを使って「/」を「\」に置換することも必要です。上では書いていませんが一応完成形を書くと、

Substitute (
  Right ( GetAsText ( オブジェクト ) ;
    Length ( GetAsText ( オブジェクト ) ) - Position ( GetAsText ( オブジェクト ) ; "win:/" ; 1 ; 1 ) - 4
  )
; "/" ; "\\" )

となります。 以降の計算式も Substitute を省いて記述していますので、適宜追加して見てください。

実はオブジェクトフィールドの参照は、ファイルを挿入ダイアログで入れずにスクリプトでパスを直接書き込むこともできます。
その場合には相対参照あるいは絶対参照のどちらかが入っていれば成立してしまうので、そのフィールドから後でパスを取得するような構造にする場合は注意が必要です。
相対パスしか入っていないフィールドに上記の計算式を使ったりすると、意味を成さない文字列になってしまいます。


オブジェクトフィールド内の相対パスの取得方法

方法2のための相対パスは、オブジェクトの種類によって書き分けます。

1. ファイルオブジェクトの相対パス

Middle ( GetAsText ( オブジェクト ) ;
  Position ( GetAsText ( オブジェクト ) ; "file:" ; 1 ; 1 ) + 5 ;
  Position ( GetAsText ( オブジェクト ) ; "filewin:" ; 1 ; 1 )
    - Position ( GetAsText ( オブジェクト ) ; "file:" ; 1 ; 1 ) - 5
)

2. 画像オブジェクトの相対パス

Middle ( GetAsText ( オブジェクト ) ;
  Position ( GetAsText ( オブジェクト ) ; "image:" ; 1 ; 1 ) + 6 ;
  Position ( GetAsText ( オブジェクト ) ; "imagewin:" ; 1 ; 1 )
    - Position ( GetAsText ( オブジェクト ) ; "image:" ; 1 ; 1 ) - 6
)

相対パスの始まりを検出する場合、有用な共通文字列がないのでオブジェクトの種類によって分けています。上記では「e:」が共通してはいますが、絶対パスに「E:」があった場合に区別できません。

file の場合で説明すると、Middle 関数を使って

  • 先頭文字位置は「file:」の位置 + 5(file:の文字数)
  • 文字数は「filewin:」の位置 – 「file:」の位置 – 5(file:の文字数)

を指定しています。

絶対パスの場合と同じように、絶対パスしか入っていないフィールドに相対パス用の計算式を使ったりすると、意味を成さない文字列になってしまいますので注意が必要です。

よって、方法2は本体ファイルのフォルダパスを前に継げて

Substitute ( Get ( ファイルパス ) ; [ "file:/" ; "" ] ; [ Get ( ファイル名 ) & ".fp7" ; "" ] ) & 相対パス

となります。


相対パスの記述法

これは特別な情報ではなく、一般的な相対パスの記述の確認です。
例として、本体ファイルから見た test.txt というファイルの場所と相対パスの記述を示します。

  • 同フォルダ内 … 「.\test.txt」 または 「test.txt」
  • 下位フォルダ内 … 「.\下位フォルダ名\test.txt」 または 「下位フォルダ名\test.txt」
  • 上位フォルダ内 … 「..\test.txt」

同フォルダは「.\」で表され、これは省略可能です。上位フォルダは「..\」で、「..\..\」なら2つ上位のフォルダを指します。

Eventを送信 で使用する絶対パスの中に「..\」等の記述を含めても全く問題ありません。

例えば、下の2つの記述は完全に同じファイルを指し、問題なく動作します。

  • .\test.txt
  • .\下位フォルダ名\..\test.txt

このため、「本体ファイルのフォルダパス + オブジェクト相対パス」という記述であれば、それを綺麗に(..\が入らないように)書き直す必要はありません。


ユーザーが入力したパスを使用する場合(絶対パスか相対パスか分からない場合)

ここから先は複雑な内容になります。必要な場合のみ参照。

フィールドにパスを入力してもらい、そのフィールドを Eventを送信 に渡して実行する場合の方法です。
入力を絶対パスでしてもらえれば問題ありませんが、できれば相対パスにも対応しておく方が融通が利きます。計算式でパスが絶対パスか相対パスかを判断すれば良いわけです。

ただし、フォルダ区切りを「/」と「\」のどちらで入力されるか分からないので、最初に変換することが必要です。

以下は絶対パスならそのままで、相対パスなら本体ファイルのフォルダパスに継げる記述です。

Substitute (
  Case (
    PatternCount ( Substitute ( 入力パス ; "/" ; "\\" ) ; ":\" ) = 1 ;
    入力パス ;
    Substitute ( Get ( ファイルパス ) ; [ "file:/" ; "" ] ; [ Get ( ファイル名 ) & ".fp7" ; "" ] ) & 入力パス
  )
; "/" ; "\\" )

上記は1例ですが、「:\」の有無によって判断しています。ユーザーに入力してもらうフィールドなら「filewin:/」などと書いてありませんので、「:\」の検出で済みます。
ただ、ユーザーが入力したパスがそもそも有効かどうかのエラー処理が入っていませんので、必要なら別に組み込む必要があります。

パスが有効かどうかを判断するのは、今のところ簡単な方法は浮かんでいません。
概要を書くと、

  1. 入力パスからフォルダパスを取りだす。(Left関数で最後のより前の文字列を取得)
  2. それを cmd dir /a-d “フォルダパス”>%TEMP%tmpFolderInfo.txt のようなコマンドにして Eventを送信 で実行し、フォルダ情報をテキストファイルに書き出す。
  3. そのテキストファイルのすべての行をファイルメーカーでレコードのインポートを用いて専用のテーブルに取得し、入力パスのファイル名が含まれるレコードがあるか調べる。
  4. インポートしたレコードは削除しておく

といった面倒な方法です。
実はファイルの存在確認が必要なときには今でも上のような手法を用いています。

ファイルの存在確認はバッチファイルなら if exist で判別でき、結果を echo して tmpFolderInfo.txt に出力するのも簡単なんですが、ファイルメーカーの Eventを送信 から if を含むようなコマンドを送るのは煩雑すぎます。 もし送れれば、tmpFolderInfo.txt の内容文字列を指定できるので、その1行目だけレコードのインポートをすれば良い事にはなりますが。

どちらかといえば最初の方法が好みです。

バージョン7ではファイルの挿入などにフィールド値や変数を指定しておけないので以上の方法を書いています。
もし後のバージョンでそれが可能なら、そのパスを使って判断専用のグローバルフィールドにファイルの挿入を参照保存で実行してみると楽です。挿入スクリプトステップの後、グローバルフィールドに値があればファイルは存在することになり、パスが有効であることが分かります。


相対パスの使い方について

余談です。
相対パスは Eventを送信 の計算式にそのまま記述しても動作することがあります。しかし、本体ファイルを開きなおしたりすると動作しなくなることもあります。

動作の確実性を求めるために、Eventを送信 内のパスの指定は必ず絶対パスにしておいた方が良いです。通常は本体ファイルのフォルダパスを前に継げる上記の方法です。

動作したりしなかったりという点について再現性を得ることができずに検証が不十分なのですが、ファイルメーカーが一部の機能にウィンドウズの機能を使っていることと関係あるかもしれません。
例えばファイルの保存ダイアログにおいて、一度保存を行うと次の保存時にはそのフォルダが最初から表示されます。このフォルダをファイルメーカーで事前に直接指定したり変更したりするスクリプトはありません。ここにウィンドウズの機能が使われています。

相対パスで動作したりしなかったりするのもこの点と関連があるように思っています。今のところ絶対パスにして実行する方法でエラーになったことはありませんので、それを推奨します。

Leave a comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

one × 5 =