1. ホーム
  2. スクリプト・コラム
  3. パール
  4. アプリケーションのヒント

Perlのファイルハンドルの説明

2022-01-29 20:55:42

ファイルI/Oでは、ファイルからデータを読み込むために、アプリケーションはまずOSの関数を呼び出してファイル名を転送し、ファイルへのパスを選んでファイルを開きます。この関数は、開いているファイルを一意に識別するPerlのファイルハンドルと呼ばれる連番を取得します。ファイルからデータを読み込むには、アプリケーションは関数ReadFileを呼び出し、Perlのファイルハンドルのメモリ上のアドレスとコピーするバイト数をOSに転送します。タスクが完了すると、システム関数を呼び出してファイルを閉じます。

エゴイストの哲学者を真似て人工知能のプログラムを書いた以外は、プログラムは外部と通信しないメソッドを使っています。クラスの例の3行目と4行目に "GRADES" がありますが、これは filehandle というデータ型の別のPerlファイルへの参照です。ハンドルとは、ファイル、デバイス、ソケット、パイプに付ける名前で、扱う名前を覚えやすくしたり、特定のキャッシュなどの複雑さを隠したりするためのものです(内部的には、ハンドルはC++のストリームやBASICのI/Oチャンネルに似ています)。ハンドルを使うと、異なる場所からの入力や、異なる場所への出力が容易になります。Perlが優れた言語である理由の1つは、複数のファイルと通信し、それらを一度に処理することができる点です。外部オブジェクトに良いシンボル名を付けることは、良い言語には不可欠な要素です[1]。

その他、Perlが良い言語である理由は、8ビットであること、組み込み可能であること、パターンを拡張することでPerlに他のプログラムを埋め込むことができること、などが挙げられます。簡潔で、Web上で使いやすい。環境が明確で、話がしやすい。いろいろな方法で参照できる(先に見たとおり)。要するに、言語そのものが、自分の問題で作れないほど厳密な構造になっていないのです。再びTMTOWTDIに戻ります。

ハンドルを作成し、open 関数でファイルに関連付けます。open は 2 つの引数を取ります: ハンドルと関連付けたいファイル名です。

Perlがこれらの定義済みハンドルを提供できるのは、オペレーティングシステムがすでに提供しているからです。UNIX では、プロセスは親プロセス (通常はシェル) から標準入力、出力、エラーを受け継ぎます。シェルの役割の1つは、これらのI/Oストリームを作成し、子プロセスが考える必要がないようにすることです)。
open関数を使って様々な用途のハンドル(入力、出力、パイプ)を作ることができるので、何をしたいのかを指定できるようにしておく必要があります。UNIXのコマンドラインと同じように、ファイル名に何文字か追加するだけです。

コピーコード コードは以下の通りです。

open(SESAME,"filename");#Read from an existing file
open(SESAME,"<filename");#explicitly, as above
open(SESAME,">filename");#Create a file and write to it
open(SESAME,">>filename");# write to the existing file next
open(SESAME,"|output-pipe-command");#Create an output filter
open(SESAME,"|input-pipe-command|");#Create an input filter

見ての通り、好きな名前を選ぶことができます。一旦ハンドルSESAMEが開かれると、(close(SESAME)で)明示的に閉じられるか、同じハンドルを何度も開くと別のファイルに関連付けられるまで、ファイルやパイプへのアクセスに使用することができます[3]。

開いているハンドルを開くことは、暗黙のうちに最初のファイルを閉じ、Perlのファイルハンドルとしては好ましくない、別のファイルを開くことになります。これは本当にやりたいことなのか、注意しなければなりません。時々、偶然にも、例えば open($handle,$file) したときに $handle に空の文字列 (null) が入ってしまうということが起こります。そうでなければ、ヌルハンドルで新しいファイルを開くことになります。
入力用のハンドルを開いたら(またはSTDINを使ったら)、"line read operation"<>で、1行読み込むことができるようになります。こちらは、その形状からダイヤモンド・オペレーションとも呼ばれます。このダイアモンドオペレーションには、読み込みたいハンドルが含まれています()[4]。STDIDハンドルを使って、次のように、ユーザが提供する答えを読み取ります。

空のダイアモンド操作<>は、コマンドラインで指定されたすべてのファイル、および指定されていない場合はSTDINから読み込みます。(これは、多くのUNIX"フィルタリング"プログラムの標準的な動作です。)

コピーコード コードは以下の通りです。

printSTDOUT"Enteranumber:";#Requesting a number to be entered
$number=<STDIO>;#Enter a number
printSTDOUT"Thenumberis$number";#output this number

ご紹介した例は理解できましたか?print文の中でSTDOUTは何をしているのでしょうか?これは、出力ハンドルの使い方の一つです。ハンドルはprint文の第1引数にすることができ、存在すればどこに出力するかを指示します。この例では、出力がすでにSTDOUTになっているので、ハンドルは冗長です。入力のデフォルトはSTDINで、出力のデフォルトはSTDOUTです。(クラス例の18行目では、混乱を避けるために省略しました)
また、ひとつだけわからないことがあります。上の例を試してみると、特別な空行ができることに気がつくと思います。これは、入力行を読んだときに、改行が自動的に削除されないためです(たとえば、"9"と入力した場合)。このような場合、Perlは改行を除去するためにchopとchompという関数を用意しています。chopは渡された最後の文字を無差別に除去して(返して)、chompはレコード識別子の最後だけを除去して(通常は"")その除去文字数を返しています。