■ RPG で IFS ストリーム・ファイルをオープンして読み取る
ストリーム・ファイル は一般的に固定長ではないし DB2/400 のようなレコード形式も
持っていない。
ただ最初から最後まで一本の線のように繋がっているファイルである。
RPG によってストリーム・ファイルを読み取るにはどのようにすれば良いのだろうか ?
これは原理的には C言語でストリーム・ファイルを読み取るのでも同じことである。
というような手順で行うのである。つまり容量分だけの動的なメモリを確保して
そのメモリに読み込んで使い終わったらメモリを解放するというものである。
【 サンプル:TESTRED 】
------------------------------------------------------------------------------------------- 0001.00 H DATEDIT(*YMD/) BNDDIR('QC2LE') 0002.00 F********** IFS の読み取り ******************************************** 0003.00 F* 0004.00 F* COMIPLE: 0005.00 F* CRTRPGMOD QTEMP/TESTRED SRCFILE(MYSRCLIB/QRPGLESRC) AUT*ALL) 0006.00 F* CRTPGM MYLIB/TESTRED MODULE(QTEMP/TESTRED) ACTGRP(*NEW) AUT(*ALL) 0007.00 F* 0008.00 F********************************************************************** 0009.00 D FD S 10I 0 0010.00 0011.00 D OPEN_ PR 10I 0 EXTPROC('open') 0012.00 D PATH * VALUE 0013.00 D FLAG 10I 0 VALUE 0014.00 D MODE 10I 0 VALUE OPTIONS(*NOPASS) 0015.00 D CODEPAGE 10I 0 VALUE OPTIONS(*NOPASS) 0016.00 D TOPAGE 10I 0 VALUE OPTIONS(*NOPASS) 0017.00 0018.00 D READ_ PR 10I 0 EXTPROC('read') 0019.00 D FILEID 10I 0 VALUE 0020.00 D BUFF * VALUE 0021.00 D LEN_ 10I 0 VALUE 0022.00 0023.00 D CLOSE_ PR EXTPROC('close') 0024.00 D FILEID 10I 0 VALUE 0025.00 0026.00 D LSTAT_ PR 10I 0 EXTPROC('lstat') 0027.00 D PATH * VALUE 0028.00 D INFO * VALUE 0029.00 0030.00 D INFO DS 128 QUALIFIED 0031.00 D ALLOCSIZE 5U 0 OVERLAY(INFO:47) 0032.00 0033.00 D INFO_P S * INZ(%ADDR(INFO)) 0034.00 D TRUE S 10I 0 INZ(0) 0035.00 D FALSE S 10I 0 INZ(-1) 0036.00 D PERROR_ PR EXTPROC('perror') 0037.00 D STR * VALUE 0038.00 0039.00 D O_RDONLY S 10I 0 INZ(1) 0040.00 D PATH S 14A INZ('/A001/TEST.TXT') 0041.00 D TMPLEN S 10I 0 0042.00 D BYTE_RED S 10I 0 0043.00 D RES S 10I 0 0044.00 D MSG S 80A INZ(' オープン・エラーです ') 0045.00 D ATTR S 80A INZ(' 属性が取得できません ') 0046.00 D SUCCESS S 16A INZ(' 読取り成功です ') 0047.00 D TMPBUF S * 0048.00 D ANS S 1A 0049.00 0050.00 /FREE 0051.00 FD = OPEN_(%ADDR(PATH): O_RDONLY); // ファイルをオープンする 0052.00 IF (FD < 0); 0053.00 PERROR_(%ADDR(MSG)); 0054.00 RETURN; 0055.00 ELSE; 0056.00 RES = LSTAT_(%ADDR(PATH): INFO_P);// 属性を取得 0057.00 IF (RES = FALSE); 0058.00 PERROR_(%ADDR(ATTR)); 0059.00 CLOSE_(FD); 0060.00 RETURN; 0061.00 ENDIF; 0062.00 TMPLEN = INFO.ALLOCSIZE;// 割振り長を取得 0063.00 IF ( TMPLEN > 0 ); 0064.00 PERROR_(%ADDR(SUCCESS)); 0065.00 RETURN; 0066.00 ELSE; 0067.00 TMPBUF = %ALLOC(TMPLEN);// 動的にメモリを確保 0068.00 BYTE_RED = READ_(FD: TMPBUF: TMPLEN); // READ 読取り 0069.00 DSPLY SUCCESS '' ANS; 0070.00 DEALLOC TMPBUF; // 確保したメモリを解放 0071.00 ENDIF; 0072.00 ENDIF; 0073.00 CLOSE_(FD); 0074.00 *INLR = *ON; 0075.00 /END-FREE -------------------------------------------------------------------------------------------
【 解説 】
先に紹介した open, close 関数に加えて、ここでは lstat, read 関数が新しく使用されている。
0018.00 D READ_ PR 10I 0 EXTPROC('read') 0019.00 D FILEID 10I 0 VALUE 0020.00 D BUFF * VALUE 0021.00 D LEN_ 10I 0 VALUE : 0026.00 D LSTAT_ PR 10I 0 EXTPROC('lstat') 0027.00 D PATH * VALUE 0028.00 D INFO * VALUE
● lstat 関数
lstat とはファイルの詳細な情報を取得する関数であり、
lstat 関数は システム API 解説書の中では
------- 構文 --------------------------------------------------------------- #include <sys/stat.h> int lstat(const char* path, struct stat *buf);
【 パラメータ 】
-
path (入力)
- オープンするファイルの NULL 終了パス名を指すポインター。
-
buf
- 情報を書き込む区域を示すポインター。
として定義されている。つまり IFS のパス名を与えるとファイル情報の構造体 buf が
戻り値として取得できることを示している。
lstat 関数によってこの IFSストリーム・ファイルが IFS 上で割り振られている長さ: INFO.ALLOCSIZE を
取得することができる。
IFS ストリーム・ファイルのデータは、ひとつの変数の中に読み込むのであるが、
どれだけの長さか最初は不明であり、オープンしただけではわからない。
そこで lstat 関数によってファイルの詳細情報として、割り振られている長さ: INFO.ALLOCSIZE を
取得するのである。
次にこの TMPLEN = INFO.ALLOCSIZE の長さの分だけの変数を
0067.00 TMPBUF = %ALLOC(TMPLEN);//動的にメモリを確保
によって動的なメモリを確保する。
変数 : TMPBUF は最初は
0047.00 D TMPBUF S *
として定義されているだけの単なるポインターであるが %ALLOC によって長さも定義されるので
以降は変数扱いすることができる。
次にこの長さ TMPLEN を使って read 関数によってデータを読み取るのである。
● read 関数
read 関数は システム API 解説書の中では
------- 構文 --------------------------------------------------------------- #include <unistd.h> ssize_t = read(int fildes, void* buf, size_t nbyte);
【 パラメータ 】
-
fildes (入力)
- 読み取られる記述子
-
buf (出力)
- 読み取られるバイト数が置かれるバッファーを示すポインター
-
nbyte (入力)
- 読み取られるバイト数
-
戻り値
- value read() が正常に実行されて読み取られたバイト数
-1 read() の実行でエラーがあった
として定義されている。
実際の使用では、
0068.00 BYTE_RED = READ_(FD: TMPBUF: TMPLEN); // READ 読取り
のようにして TMPBUF の中に IFSストリーム・ファイル全体が収められ、読み取られた長さは
BYTE_RED バイトであることになる。
最後には
0070.00 DEALLOC TMPBUF; // 確保したメモリを解放
のようにして DEALLOC 命令によって動的に確保したメモリを解放することを忘れてはいけない。
このサンプル: TESTRED は、どのようなツールも使わずに極めてシンプルな手法による
IFS ストリーム・ファイルを読み取る方法を示している。
システム API の構文を紹介したのは C言語の関数の構文が RPG で、どのようにプロトタイプとして
定義されているかを学習して欲しかったからである。
RPG プログラマーが C 関数を自由に使いこなせるようになれば実行可能な世界がかなり広がることになる。