8章.ファイル

8.1.ファイルのオープン

モード記述備考
入力open(FILE,"file");またはopen(FILE,"<file");
出力open(FILE,">file");
追加open(FILE,">>file");
入出力open(FILE,"+<file");ファイルが無いとエラー
入出力open(FILE,"+>file");ファイルを作成してから。既にあれば上書きされる。
入出力open(FILE,"+>>file");ファイルが無ければ作成してから。既にあれば,そのまま。


8.2.可変長ファイルの入出力

各レコードの長さが一定でないファイルを可変長ファイルと呼びます。
順(シーケンシャル)アクセスに向いています。

サンプルファイル(number.txt)

Shigeo Nagashima 33(0A)
Masaki Saitoh 11(0A)
Masumi Kuwata 18(0A)
Masahiro Kawai 0(0A)
Hideki Matui 55(0A)

(0A)は改行コード。説明の都合上,N88BASICのレコードの区切りは(0A)でもよいものとします。 実際は(0D)(0A)です。※1.3.注釈文

perlのファイルハンドルは入出力に関わらずINと命名して説明します。


8.2.1.入力

サンプルファイルのレコードを順に入力し表示します。

N88BASICでは

1000 OPEN "NUMBER.TXT" FOR INPUT AS #1
1010 IF EOF(1) THEN CLOSE:END
1020 LINE INPUT #1,A$
1030 PRINT A$
1040 GOTO 1010

perlでは,1レコード入力の基本形は$a = <IN>;です。

open(IN,"number.txt");
while($a = <IN>) {
  chop($a);
  print "$a\n";
}  
close(IN);

全てのデータを配列に代入してから表示する方法も有ります。

open(IN,"number.txt");
chop(@x = <IN>);
close(IN);
#
foreach $a (@x) {
  print "$a\n";
}  

説明上,特殊変数$_は利用していません。chop()はレコード末尾の(0A)を切り捨て。


8.2.2.出力

N88BASICでは

1000 OPEN "NUMBER.TXT" FOR OUTPUT AS #1
1010 A$="Eiji Sawamura 14"
1020 PRINT #1,A$
1030 CLOSE

perlでは

open(IN,">number.txt");
$a = "Eiji Sawamura 14";
print "$a\n";
close(IN);


8.2.3.追加出力

N88BASICでは

1000 OPEN "NUMBER.TXT" FOR APPEND AS #1
1010 A$="Eiji Sawamura 14"
1020 PRINT #1,A$
1030 CLOSE

perlでは

open(IN,">>number.txt");
$a = "Eiji Sawamura 14";
print "$a\n";
close(IN);


8.3.固定長ファイルの入力

各レコードの長さが同じファイルを固定長ファイルと呼びます。
乱(ランダム)アクセスに向いています。

サンプルファイル(number2.txt)

Shigeo   Nagashima 33(0A)
Masaki   Saitoh    11(0A)
Masumi   Kuwata    18(0A)
Masahiro Kawai     0 (0A)
Hideki   Matui     55(0A)

(0A)は改行コード。レコード長は22バイトです。

N88BASIC(N88BASIC /S:22と起動しています)では

1000 OPEN "NUMBER.TXT" AS #1
1010 FIELD #1,22 AS A$
1020 GET #1,3  '3番目を入力
1030 PRINT A$
1040 GET #1,5  '5番目を入力
1050 PRINT A$
1060 CLOSE

Masumi   Kuwata    18
Hideki   Matui     55

perlでは

open(IN,"number.txt");
$p = 2; #ファイルの先頭は0で2は3番目
seek(IN,$p*22,0);
$l = read(IN,$a,22);
if ($l != 22) { $a = "error\n"; }
chop($a);
print "$a\n";
#
$p = 4; #4は5番目
seek(IN,$p*22,0);
$l = read(IN,$a,22);
if ($l != 22) { $a = "error\n"; }
chop($a);
print "$a\n";
close(IN);

seek(IN,x,0);でファイルの先頭(0)から数えてxバイト目へ位置づけして, そこからread(IN,$a,y);で$aへy文字分読み込みます。

seek関数

seek(ファイルハンドル,位置,起点)
位置 起点からの位置。起点の値が1か2のときは負の値でも良い。
起点 0:ファイルの先頭,1:現在の位置,2:ファイルの末尾


8.4.ランダムアクセスを利用したカウンタファイル

ランダムアクセスを利用すれば一回のオープンでカウンタファイルの更新が可能ですので ロック機能が中断されることは有りません。

count.txt

0001(0A)

open(IN,"count.txt");
chop($x = <IN>);
close(IN);
$x++;
if ($x > 9999) { $x = 1; }
$x = substr("0000$x", -4);
open(IN,">count.txt");
flock(IN,2); #排他
print IN "$x\n";
close(IN);

この場合,open(IN,">count.txt")からflock(IN,2)の間に別のプロセスが, このファイルを参照した場合に0になってしまいますので内容が壊れてしまいます。

open(IN,"+<count.txt"); #入出力オープン
flock(IN,2); #排他
read(IN,$x,4); # chop($x = <IN>);
$x++;
if ($x > 9999) { $x = 1; }
$x = substr("0000$x",-4);
seek(IN,0,0);
print IN "$x\n";
close(IN);

この場合,open(IN,"+<count.txt")からflock(IN,2)の間に別のプロセスが, このファイルを参照した場合には少なくとも0にはなりませんので,カウントが重複するだけで済みます。
4桁を超えたら1に戻るようになっています。

ただカウントするだけなら

open(IN,"+<count.txt"); #入出力オープン
flock(IN,2); #排他
chop($x = <IN>);
$x++;
seek(IN,0,0);
print IN "$x\n";
close(IN);


8.5.ランダムアクセスを利用した任意のレコードの更新

ランダムアクセスを利用すれば任意のレコードの内容を書き換えることが可能です。

サンプルファイル(index.txt)

0001(0A)
abcd(0A)
ijkl(0A)
ijkl(0A)
mnop(0A)

(0A)は改行コード。レコード長は5バイトです。

N88BASIC(N88BASIC /S:5と起動しています)では

1000 OPEN "INDEX.TXT" AS #1
1010 FIELD #1,5 AS A$
1020 P=3  '3番目を更新
1030 LSET A$="efgh"+CHR$(&HA)
1040 PUT #1,P
1050 CLOSE

perlでは

open(IN,"+<index.txt");
$p = 2;
$a = "efgh\n";
seek(IN,$p*5,0);
print IN "$a";
close(IN);

更新後のサンプルファイル

0001(0A)
abcd(0A)
efgh(0A)
ijkl(0A)
mnop(0A)

先頭(0)から数えて2X5=10文字目からefgh(0A)を上書きする事になります。
もし,レコード長よりも長いあるいは短い文字を書いた場合はそのままの長さ分だけ 指定した位置から上書きされます。


[HOME]

Copyright (c)1996 GOMASUKE
Since 09/09/1996, Last Updated 10/05/1996