エラーに備えよう

エラーは恐くない

 プログラムを実行すると、エラーが発生する事があります。これはもう避けられない事です。
 このエラーダイアログが出たからと言って、過剰に恐れる必要はありません。

 エラーダイアログが出ると言う事は、問題が軽い事、もしくは事実上問題でない事と思っても構いません。
 というのも、本当に問題となる事態は、エラーが発生しないで突然、または静かに起きるからです。
 エラーが発生してエラーダイアログが出ると言う事は、「安全に」エラーが処理された証拠として、むしろ安心してもいい事といえます。

 特にAppleScriptでは、エラーが出た場合も、かなり安全に終了できるようになっているので、どんどん発生させたって構いません。
 今回は、発生するエラーを怖がらず、味方に付ける方法を紹介します。

エラーを無視する

 スクリプトの実行中にエラーが発生すると、処理が中断してしまいます。
 しかし、try文でひとまとめにした処理はエラーを無視できます。
 エラーが出た場合は、on error以下のスクリプトに処理が移ります(注1)。

try
	null * 10 -- エラー発生
on error
	-- エラーが発生しない場合は実行されない
end try

 このようにスクリプト全体をtry〜on error〜end try文で囲んでしまえば、エラーがまったく発生しないスクリプトを作成することもできます。
 しかし、エラーの発生した場所の特定は難しくなりますし、本当に重要な問題が起きても気づけなくなります。
 try文は必要な部分だけに使いましょう。

 また、try文ではエラーの発生を利用することも可能です。
 例えば、ダイアログ関連のOSAXでは、キャンセルが押されるとエラー番号「-128」のエラーが発生します。
 つまり、これをtry文で囲むことで処理を続行できるわけです。

 次のハンドラは[OK]が押されたときは"OK"、キャンセルが押された場合もスクリプトを終了せずに"Cancel"を返します。

noExitDialog("キャンセルのサンプル")

on noExitDialog(theCaption)
	try
		return button returned of (display dialog theCaption)
	on error
		return "Cancel"
	end try
end noExitDialog

ファイルは必ず閉じる

 簡単なファイルの読み書きについては「ファイル指定を覚えよう」で解説しましたので、ここではさらに細かいファイル処理の方法について解説します。

 ファイル操作は、次のような流れで処理されます。

  1. ファイルを開く
  2. ファイルのデータの読み書きをする
  3. ファイルを閉じる

 ここで重要な操作が、ファイルを閉じる処理です。
 ファイルを閉じる処理を忘れてしまうと、ほかのプログラムにも影響を与えることになりますので注意してください。
 これはまさに、エラーダイアログのでない「本当に重要な問題」です。

 これらのことから、ファイルを開いてから閉じるまでの処理はできるだけ素早く済ますことと、エラーが発生しても確実にファイルを閉じることができるようにtry文を使って処理することが鉄則です。

 次のハンドラは、テキストファイルの内容をすべて読み込んで結果ウィンドウに表示します。

readTextFile(choose file of type {"TEXT"})

on readTextFile(theFile)
	open for access theFile
	try
		set textData to read theFile
	end try
	close access theFile
	return textData -- 読み込んだテキスト
end readTextFile

 このスクリプトでは、次のような処理を行っています。

  1. エイリアス値であるchoose file命令の結果を変数theFileに代入
  2. open for access命令を使ってファイルを開く
  3. read命令を使ってファイルの内容を変数textDataに代入
  4. close access命令でファイルを閉じる

 なお、ここで紹介した命令はすべてOSAX命令です。

 ファイルを開くopen for access the Fileとファイルを読み込むset text Data to read theFileの部分を、try文で囲んでいる点に注目してください。
 このtry文によって、エラーの有無にかかわらずファイルを必ず閉じることができます。

 次に、テキストファイルの一部を読み込む処理を紹介します。
 ここでは特定の文字で区切る方法を解説しておきます。

 次のスクリプトは、テキストファイルの先頭の二行だけを読み込みます。

read2Lines(choose file of type {"TEXT"})

on read2Lines(theFile)
	open for access theFile
	try
		set textData to read theFile until return 
		set textData to textData &(read theFile before return)
	end try
	close access theFile
	return textData
end read2Lines

 このスクリプトでは、改行(return)を区切り文字として使って、テキストファイルの先頭の2行を取り出しています。
 read命令を連続して使うことで、先に読み込んだデータ(1行目)に続くデータ(2行目)を読み込めるわけです。
 さらに多くのデータを続けて読み込みたい場合は、repeat文を使えば便利でしょう。

 set textData to text Data & (read the File before return)beforeが使われていますが、この場合は区切り文字の直前まで読み込めます。
 このbeforeの部分をuntilに書き換えると区切り文字も含めて読み込むことになります。

テキストファイルを書き出してみる

 今度は、文字列をファイルとして書き出してみましょう。
 前述したように、新しくファイルを作る際にエイリアス値は使えないので、ファイル参照で指定します。
 ファイル参照はa reference to命令を使えば変数に代入できましたね。

 ファイルをスクリプトへ書き出す場合も、基本的な流れは読み込みの場合と同じです。
 ただし、open命令に書き換え許可を意味するwith write permissionの引数を付ける必要があります。

 また、ファイル全体を書き換える場合は、必ずset eof命令でファイルの末尾を「0」にしておくことを忘れずに。
 この作業を怠ると、ファイルを上書きする際に上書きされる側のファイルのデータが残ってしまうことがあります。

 次のスクリプトは、"保存する文"という文字列をテキストファイルとして書き出します。

writeString(choose file name, "保存する文")

on writeString(theFile, theString)
	open for access theFile with write permission
	try
		set eof theFile to 0
		write theString to theFile
	end try
	close access theFile
end writeString

 先ほどの説明と矛盾しているようですが、choose file name命令の結果はファイル参照ですが変数に代入できます。
 これは、choose file name命令がa reference to命令の役割を兼ねているからです。
 また、readと同様にwriteを連続して記述すると、ファイルを続きから書き出せます。

 新規ファイルは自動的にSimpleText形式(クリエータ:ttxt)のテキストファイル(ファイルタイプ:TEXT)となりますが、上書きした場合は既存のファイルのクリエータとファイルタイプがそのまま残ります。

 open for access命令は、結果を数値で返します。
 これはファイルの「参照番号」を示す数値で、「参照」の代わりにスクリプト中で使えます。
 また、「参照」を使った場合よりも処理速度が速いという特徴があります。
 頻繁にファイルの読み書きを行う場合は、「参照番号」を使って処理することを強くお勧めします。

 では、先ほどのスクリプトを「参照番号」を使って書き換えてみましよう。

writeString(choose file name, "保存する文")

on writeString(theFile, theString)
	set fileNumber to (open for access theFile with write permission)
	try
		set eof fileNumber to 0
		write theString to fileNumber
	end try
	close access fileNumber
end writeString

 C言語の書籍などでは、ファイルの入出力を重要な処理として紹介していることが多いのですが、AppleScriptではアプリケーションの機能を利用してファイルの入出力を行うことが多いため、重要度はさほど高くありません。
 しかし、使えると強力な武器になりますので、覚えておいて損はないでしょう。

 AppleScriptではPICTなどのテキスト以外のデータ(バイナリデータ)のファイル操作も可能ですが、使いやすいものとは言えません。
 よほどでない限り、専用のOSAXやアプリケーションを利用することをお勧めします。

さらにエラーを知る

 さらにエラーを便利に使えるように、エラーを定義して、積極的にエラーを発生させる事もできます。

 エラーを発生させるのはerror命令です。
 さっそくエラーを発生させてみましょう。

error

 display dialog命令でダイアログを表示させてもいいのですが、すぐにスクリプトを終了させていい場合は、こちらの方が簡単に使えますし、エラーダイアログの形をしているので、ユーザーにより注意を促す効果もあります。

 それぞれのエラーには、エラー番号がついているので、それを参照する事で、どのようなエラーが発生したか分かります。
 エラー番号は、try文のon errorの後に引数を指定する事で取り出せます。

 次のスクリプトは、定義されていない(値の代入されていない)変数であるxを使っているので、エラーが発生します。
 それをon error以下のブロックで受け取っています。

try
	x
on error number n
end try
n
	--> -2753

 発生するエラーの種類毎についている番号は、環境を問わず一定なので、番号を調べて処理分けする事ができます。
 番号をチェックした後、tryブロック内で発生する事を想定していないエラーは、error命令で再度発生させると良いでしょう。
 大体次のような流れになります。

try
	エラーの発生する可能性のある処理
on error theCaption number n
	if n = (処理したいエラーの番号) then
		発生したエラーに対する処理
	else
		error theCaption number n
	end if
end try

 想定しているエラーに対しては処理を行い、それ以外のエラーに対しては再度エラーを発生させています。
 ここでは、エラー番号の他にエラーダイアログに表示する文字列(theCaption)も取得しています。
 エラー時に受け取る事ができる値は、他にもいくつかが存在していますが、値が返らない状況も多いため使う機会は限定されます。
 とりあえず、この二つを知っておけばいいでしょう。

 比較的エラー処理が甘いスクリプトを書いても構わないAppleScriptですが、エラー処理をきちんと行う必要がある場面もあります。
 また、エラーを利用した方が、スクリプトがすっきりかける場合もあります。このtry文の使い方に慣れておいて損は無いでしょう。

【今回のまとめ】

ファイルの入出力は、

  • 開く/出し入れする/閉じる
  • 「try」文を使ってエラーでも必ずファイルを閉じることが鉄則
  • 「参照」か、「参照番号」を変数に代入して処理する

エラーの性質は、

  • エラーダイアログは、正常にエラーが処理された証拠
  • エラーには固有の番号がある