要約: | - Curl®言語のソース オブジェクトは、2 つのカテゴリであるファイルとディレクトリに分けられます。
ファイル という用語は、Curl 言語でデータの読み取りや書き込みを行なうリソース オブジェクトを指します。ディレクトリ はファイルや他のディレクトリのコレクションで、ファイル システムにあるディレクトリに似ています。
|
この章の前半のセクションでは、リソースの識別、読み取り、書き込みの方法について説明しました。通常これらのタスクを実行するときは、その対象となる構造や基礎となるオブジェクトのことを考える必要はありません。これとは別に、リソース オブジェクトそのものの情報が必要になる場合があります。たとえば、ファイルの更新時刻を取得したりディレクトリの内容を表示する場合などでは、直接リソース オブジェクトにアクセスする必要が生じます。
注意: アプレットがローカル ファイル システムにあるファイルにアクセスするためには、特権が必要です。セキュリティの観点から、このドキュメントの例では特権を付けると実行されません。そのため、このセクションでは実行可能な例ではなく、ソースコードでの例を提供します。コードをアプレット ファイルにコピーして特権のあるロケーションから実行してください。詳細は「
特権付きアプレット」を参照してください。
Curl 言語リソース オブジェクトは、2 つのカテゴリであるファイルとディレクトリに分けられます。
ファイル
という用語は、Curl 言語でデータの読み取りおよび書き込みを行うリソース オブジェクトを指します。ファイルには、ファイル システムのファイル、Web サーバー上のページ、文字列ファイルおよびその他のオブジェクトがあります。
Curl 言語では、ファイルは
File クラスで表されます。このクラスには、アクセス可能なさまざまなファイルの種類を表すサブクラスがあります。
これらのクラスの詳細については、『API リファレンス』を参照してください。
サブクラスにしかないメソッドやアクセッサを必要とする場合を除き、通常はサブクラスではなく File クラスを使用することを推奨します。また、アクセスを要するリソース オブジェクトが適切なサブクラスに属していることを確認する必要があります。
ディレクトリ
はファイルや他のディレクトリのコレクションで、ファイル システムのディレクトリに似ています。Curl 言語では、ディレクトリは
Directory クラスで表されます。このクラスにはあらゆる種類のディレクトリが含まれています。ディレクトリは、ファイル システム内、Web サーバー上、およびディレクトリに似た構成でグループ化されたリソースを含むその他のシステムに存在します。
Directory クラスは抽象的な方法でディレクトリの内容へのアクセスを提供しているため、通常はアクセスするディレクトリの種類を気にする必要はありません。ただし操作の中には特定の種類のディレクトリにしか意味をなさないものがあり、したがって作業対象のディレクトリの種類を確定する必要が生じる場合もあります。
Directory クラスには、さまざまな種類のディレクトリを表すサブクラスが多数含まれています。
通常
File または
Directory オブジェクトは、アクセス対象のリソ-スを識別する
Url オブジェクトの
resolve メソッドを呼び出してインスタンスを作成します。
Url.resolve は
any を返します。これは、
Url が何を指すかによって
File または
Directory クラスのいずれかのインスタンスになります。
{value
let myurl:Url = {url "support/io/example.txt"}
let resource:any = {myurl.resolve}
}
次の例では、URL を入力して、それに対して resolve メソッドがクラスを返します。URL が識別する File または Directory のサブクラスを識別します。この例のコードをアプレットにコピーし、特権のあるロケーションから実行してください。
{import * from CURL.IO.HTTP}
{define-proc {typed-file-list uri:String}:String
let id:String = "<error>"
{try
|| 解析の結果が例外になる場合に注意してください。
let uriobj:any = {{url uri}.resolve}
|| 結果が何か判別してください。解析された結果が各クラスと一致するかチェックします。
{type-switch uriobj
case hd:HttpDirectory do
set id={String uri, " is an HttpDirectory."}
case hf:HttpFile do
set id={String uri, " is an HttpFile."}
case ld:LocalDirectory do
set id={String uri, " is a LocalDirectory."}
case lf:LocalFile do
set id={String uri, " is a LocalFile."}
case sd:StringDirectory do
set id={String uri, " is a StringDirectory."}
case sf:StringFile do
set id={String uri, " is a StringFile."}
case f:File do
set id={String uri, " is a File."}
case od:ObjectDirectory do
set id={String uri, " is an ObjectDirectory."}
else
set id={String uri, " is something I can't identify!"}
}
|| 入力した URL が見つからないときに実行します。
catch err:MissingFileException do
set id = {String uri, " not found."}
catch err:FileException do
set id = {String uri, " not found."}
|| KeyNotFound の例外は URL を存在しない curl:// スキームの
||トップで解析しようとした場合に起こります。
catch err:KeyNotFoundException do
set id = {String uri, " not found. Stop messing around in the curl:// hierarchy!"}
} || try
{return id}
}
URL を入力して、{bold What is it?} を、この例では、URL を解決して、もしあれば、その URL に存在するオブジェクトのクラスを知らせます。
{value
let dirfield:TextField =
{TextField width=2in, value="."}
let results:Graphic =
{Fill}
let clickme:CommandButton =
{CommandButton
label="What is it?",
{on Action do
set results =
{results.replace-with
{TextFlowBox
{typed-file-list dirfield.value}
}
}
}
}
{spaced-vbox
{spaced-hbox {text URL to probe:}, dirfield},
{spaced-hbox {Fill}, clickme},
{spaced-hbox results}}
}
Curl 言語には、
Url の変換によって
File または
Directory のどちらのオブジェクトが返されるかをすばやく判定する 2 つのプロシージャがあります。これは 1 種類のオブジェクトしか扱わない場合に役に立ちます。これらのプロシージャが
true を返す場合、
Url で識別されるオブジェクトが存在すること、および
File または
Directory のいずれかであることを意味します。
{value
let extfield:TextField =
{TextField width=2in, value="."}
let extresults:Graphic =
{Fill}
let extbutton:CommandButton =
{CommandButton
label="Does it exist?",
{on Action do
set extresults =
{extresults.replace-with {TextFlowBox}}
let exturl:Url = {url extfield.value}
{if {local-file-exists? exturl} then
{extresults.add
{text {value exturl}
is a File. }
}
else
{extresults.add
{text {value exturl}
is {text color = "red", not}
a File. }
}
}
{if {local-directory-exists? exturl} then
{extresults.add
{text {value exturl}
is a Directory.}
}
else
{extresults.add
{text {value exturl}
is {text color = "red", not}
a Directory.}
}
}
}
}
{VBox
{HBox {text Enter a URL:}, extfield},
{HBox {Fill}, extbutton},
{HBox extresults}}
}
注意: ファイルやディレクトリにアクセスする前にその存在が確認されていても、アクセス時に必ず MissingFileException がキャッチできるようにしておく必要があります。この理由は、たとえば上記のプロシージャを使用してファイルの存在を確認してから、実際にアクセスするまでの間にファイルが削除されている可能性があるためです。もちろん、スローされる可能性のある他の例外もキャッチする必要があります。
Url を
Directory オブジェクトに変換したら、このオブジェクトを使用してディレクトリに関する情報にアクセスできるようになります。以下のセクションでは、ディレクトリの内容にアクセスしたりその他の情報を取得する方法について説明します。
次の例では、ディレクトリの内容を繰り返して処理しています。
typed-file-list プロシージャに URL が渡されて変換されます。変換されたオブジェクトが
Directory の場合、オブジェクト内のキーを繰り返し処理してオブジェクト名を
StringBuf に追加します。さらに、キーで指定されるファイルまたはディレクトリを表すオブジェクトのインスタンスを作成します。このオブジェクトがディレクトリまたはシンボリック リンクの場合、プロシージャはオブジェクトの名前に
/ または
@ を追加して、普通のファイルと区別します。この例のコードをアプレットにコピーし、特権のあるロケーションから実行してください。
{define-proc {typed-file-list diruri:String}:String
let keys:StringBuf = {StringBuf ""}
{try || ファイル関連のエラーをキャッチします
let dir:any = {{url diruri}.resolve}
|| 返却されたオブジェクトが Directory であることを確認します。
{if dir isa Directory then
|| ディレクトリ内の全てのファイルをチェックするループ構文です。
{for key k:String in dir do
{keys.concat k}
|| 各ファイルを検証します。 ディレクトリならばファイル名に / を追加します。
let obj:any = {dir.get k}
{if obj isa Directory then
{keys.append '/'}
}
|| シンボリック・リンクならば '@' をファイル名に追加します。
{if obj isa String then
{keys.append '@'}
}
{keys.append ' '}
}
else
{set keys =
{StringBuf diruri & " is not a directory."}
}
}
|| 指定した URL に何も存在しない場合に実行します。
catch err:MissingFileException do
{set keys = {StringBuf "Directory " & diruri & " not found."}
}
} || try
|| 結果を文字列に変換して返却します。
{return {keys.to-String}
}
}
|| UI部分: テキストボックスとボタンが上記のプロシージャを呼び出し、
|| スペースが結果を保持します。
{value
let dirfield:TextField =
{TextField width=4in, value="."}
let results:Graphic =
{Fill} || ディレクトリ リストの結果を保持します。
let clickme:CommandButton =
{CommandButton
label="List Directory",
|| プロシージャを呼び出し、現在ボックスが保持しているコンテンツを
|| 新規の結果と入れ替えます。
{on Action do
set results =
{results.replace-with
{TextFlowBox {typed-file-list dirfield.value}
}
}
}
}
|| 要素を整理し表示します。
{spaced-vbox
{spaced-hbox {text Directory URL:}, dirfield},
{spaced-hbox {Fill},clickme},
{spaced-hbox results}}
}
Directory クラスには、それで表されるディレクトリに関する情報やその下にあるファイル システムの詳細を取得するためのいくつかのメソッドやアクセッサが用意されています。
次のようなアクセッサがあります。
Directory クラスのメソッドにより、URL の操作や新しいUrl の作成が可能になります。
上記では、concat メソッドがおそらく最も頻繁に使用するメソッドでしょう。これを使用すると、Directory から (たとえば、その中にあるファイルにアクセスするために) 新しい Url を簡単に作成することができます。次の例で、ディレクトリの URL とそれに連結するパスを入力してみてください。この例のコードをアプレットにコピーし、特権のあるロケーションから実行してください。
{value
|| URLとパスを入力するフィールドと結果を表示するスペースを作成します。
let urlfield:TextField =
{TextField width = 4in, value="."}
let concatfield:TextField =
{TextField width = 4in, value="foo.curl"}
let result:Graphic =
{Fill}
|| このボタンで全ての作業を行います。
|| クリックすると URL がディレクトリを指しているかをチェックし、
|| 正しい場合は Directory オブジェクトを作成し、concat メソッドを使用します。
let doconcat:CommandButton =
{CommandButton
label="Concat!",
{on Action do
let theurl:Url = {url urlfield.value}
|| URL がディレクトリ名であるか確認します。
{if not {in-local-filesystem? theurl} or
{local-directory-exists? theurl}
then
|| 正しい場合は Directory オブジェクトを入手します。
let thedir:Directory =
{theurl.resolve}
|| パスを連結します。
let newurl:Url =
{thedir.concat concatfield.value}
|| 結果を渡します。
set result =
{result.replace-with
{TextFlowBox
{paragraph The Url
{text color="red",
{value theurl.name}}
concatenated with
{text color="red",
{value concatfield.value}} is
{text color="green",
{value newurl.name}}.}
}
}
else || 既存のディレクトリを指定しなかった場合
set result =
{result.replace-with
{TextFlowBox
{paragraph Hey!
{text color="red",
{value theurl.name}}
isn't a directory.}
}
}
}
}
}
|| UI を配置します。
{spaced-vbox
{spaced-hbox {Fill}, {text Url:}, urlfield},
{spaced-hbox {Fill}, {text Path to concat:}, concatfield},
{spaced-hbox {Fill}, doconcat},
{value result}
}
}
create-Directory プロシージャを使用してファイル システム上で新しいディレクトリを作成します。このプロシージャは
Url を引数として、新しいディレクトリを表す
Directory オブジェクトを返します。既定では、そのディレクトリがファイル システムにすでに存在する場合に
IOException がスローされます。
error-if-exists? オプションを
false に設定すると、この動作を変更することができます。
Url を
File オブジェクトに変更したら、オブジェクトを使用してリソースに関する情報を取得することができます。
次の表は、役に立つ情報を提供する
File クラスのアクセッサを一覧したものです。完全な詳細については、『API リファレンス マニュアル』の
File の項目を参照してください。
アクセッサ | 説明 |
exists? | ファイルが変換された場合に true を返します。これは通常ファイルが存在することを意味します。 |
parent-dir | このファイルが存在するディレクトリを表す Directory オブジェクトを返します。 |
when-last-accessed | ファイルが最後にアクセスされた日付と時刻を表す DateTime オブジェクトを返します。ファイルが存在するファイル システムからこの情報を取得できない場合、このメソッドは null を返します。 |
when-last-modified | ファイルが最後に書き込まれたかまたは別の方法で変更された時間を表す DateTime オブジェクトを返します。ファイルが存在するファイル システムからこの情報を取得できない場合、このアクセッサは null を返します。 |
writable? | ファイルが書き込み可能な場合に true を返します。 |
この例のコードをアプレットにコピーし、特権のあるロケーションから実行してください。
{value
let results:TextFlowBox = {TextFlowBox}
let myurl:Url = {url "io-directory-file-classes.curl"}
let myfile:File = {myurl.resolve}
{results.add
{paragraph This file is located in
{value {value myfile.parent-dir}.name}.}}
{results.add
{paragraph It was last accessed
{value myfile.when-last-accessed}.}}
{results.add
{paragraph It was last modified
{value myfile.when-last-modified}.}}
{if myfile isa LocalFile and (myfile asa LocalFile).writable? then
{results.add {paragraph The file {bold is} writable.}}
else
{results.add {paragraph The file {bold is not} writable.}
}
}
{value results}
}
File クラスのメソッドの多くはプロシージャとして直接使用することができます (たとえば、
File.write-open を
write-open プロシージャで呼び出せます)。ファイルにアクセスするために
File オブジェクトのインスタンスを作成する必要がないという点で、プロシージャを使用する方が便利です。
上記の情報以外に、
LocalFileInfo クラスからファイルの情報を得ることもできます。ANSI C の
struct stat
から得られる情報と同じような情報を提供します。このクラスのオブジェクトを直接インスタンス化することはできません。代わりに、
LocalFile クラスの
info メソッドを使用する必要があります。これは、
File クラスの
LocalFile サブクラスが特別に必要となるケースの 1 つです。
ファイル システムのファイルを操作するには、ファイルを含むディレクトリを表す
Directory オブジェクトをインスタンス化します。ファイル操作がより簡単になるように、Curl 言語ではファイル システムのファイルを直接操作するプロシージャがいくつか用意されています。これらのプロシージャは、ローカル ファイル システムのファイルを識別する
Url オブジェクトのみを対象にしています。
プロシージャ | {copy from:Url, to:Url, error-if-exists?:bool=true, recurse?:bool=false}:void |
説明 | from で指定されたファイルを to で指定された場所にコピーします。to URL は、コピー先のファイルまたはディレクトリの名前になります。単にコピー先のディレクトリ 1 つを指しているのではありません。recurse? が true で from がディレクトリを指す場合、ディレクトリとその内容、およびその配下のディレクトリの内容もすべてコピーされます。 |
例外 | IOException がスローされるのは次のような場合です。- error-if-exists? が true で、ファイルまたはディレクトリがすでに to に存在する場合。
- from がディレクトリで、recurse が false の場合。
PermissionDeniedFileException がスローされるのは次のような場合です。- ユーザーが from の読み取り権限を持っていない場合。
- ユーザーが to を作成するための書き込み権限を持っていない場合。
|
次の例で、2 つの URL を入力してみてください。1 つは存在するファイルの URL、もう 1 つはファイルのコピー先の場所を識別する URL です。サンプルコードをアプレット ファイルにコピーして、特権ロケーションから実行してください。
{value
let copyfrom:TextField =
{TextField width=4in}
let copyto:TextField =
{TextField width=4in}
let copyresult:Graphic =
{Fill}
let recurse-button:CheckButton =
{CheckButton || OK to copy a directory?
label = "Recurse?"}
let overwrite-button:CheckButton =
{CheckButton || OK to overwrite a file?
label = "Overwrite?"}
let docopy:CommandButton =
{CommandButton
label = "Copy",
{on Action do
{if (copyfrom.has-value? and copyto.has-value?) then
{try || Catch any exceptions thrown by copy
{copy {url copyfrom.value},
{url copyto.value},
recurse? = recurse-button.value,
error-if-exists? = overwrite-button.value}
|| Update message indicating successful copy
set copyresult =
{copyresult.replace-with
{TextFlowBox "Copied " & copyfrom.value
& " to " & copyto.value}}
|| Catch possible exceptions caused by copy?
catch err:MissingFileException do
set copyresult =
{copyresult.replace-with
{TextFlowBox copyfrom.value &
" does not exist!"}}
catch err:PermissionDeniedFileException do
set copyresult =
{copyresult.replace-with
{TextFlowBox "Permission to read " &
copyfrom.value &
" or write to " &
copyto.value &
" denied."}}
catch err:IOException do
set copyresult =
{copyresult.replace-with
{TextFlowBox copyfrom.value &
" is a directory and you " &
" did not check Recurse?," &
" or you are trying to " &
" overwrite a file and " &
" Overwrite? is not checked."
}
}
} || Try
else || One of the TextFields was blank
set copyresult =
{copyresult.replace-with
{TextFlowBox "You must supply a value " &
" in both boxes!"}}
}|| If
}
}
{spaced-vbox width=6in,
{spaced-hbox
{Fill},
{text Copy from:},
copyfrom
},
{spaced-hbox
{Fill},
{text Copy to:},
copyto
},
{spaced-hbox
{Fill},
{VBox
recurse-button, overwrite-button},
{Fill}, docopy},
{spaced-hbox {text Message:}, copyresult}
}
}
プロシージャ | {delete url:Url, error-if-missing?:bool=true, recurse?:bool=false}:void |
説明 | url で指定されたファイルまたはディレクトリを削除します。url がディレクトリを識別し、recurse が true の場合、ディレクトリとともにその内容および配下の内容がすべてが削除されます。 |
例外 | recurse が false で url がディレクトリの場合は、 IOException がスローされます。 |
プロシージャ | {rename from:Url, to:Url, error-if-exists?:bool=true}:void |
説明 | from にあるファイルまたはディレクトリの名前を to に変更します。from のステム パスが to と異なる場合は、ファイル名が変更されるだけでなく to で指定された場所へファイルが移動します。 |
例外 | IOException がスローされるのは次のような場合です。 - to の最後のファイル名またはディレクトリ名の上位のディレクトリが存在しない場合
- from にファイルもディレクトリも存在しない場合
- to がすでに存在し、error-if-exists? が true の場合
|
プロシージャ | {symlink url:Url, linked:String}:void |
説明 | ファイルまたはディレクトリの pathname へのシンボリック リンクである linked を作成します。path は linked と相対的な位置にあるファイルまたはディレクトリを指す String です。pathnameで指定されたファイルまたはディレクトリが実際に存在するかどうかはチェックされません。結果として、壊れたシンボリック リンクがファイル システムに生成される可能性もあります。 |
例外 | FileException がスローされるのは次のような場合です。 - ファイル システムがシンボリック リンクをサポートしない場合。
- ファイルまたはディレクトリがすでに linked に存在する場合。
linked のパスで指定されたディレクトリが存在しない場合は、MissingFileException がスローされます。 プログラムが linked を作成する権限を持っていない場合は、PermissionDeniedFileException がスローされます。 |
Copyright © 1998-2019 SCSK Corporation.
All rights reserved.
Curl, the Curl logo, Surge, and the Surge logo are trademarks of SCSK Corporation.
that are registered in the United States. Surge
Lab, the Surge Lab logo, and the Surge Lab Visual Layout Editor (VLE)
logo are trademarks of SCSK Corporation.