前へ | 次へ | 目次 | 索引 |
RMS の順編成ファイルはレコード・モードまたはストリーム・モードでオープンすることができます。デフォルト設定では,STREAM_LF ファイルはストリーム・モードでオープンされます。他のすべてのファイル・タイプはレコード・モードでオープンされます。ファイルをオープンするときに,省略可能な引数 "ctx=rec" を指定することで,これらのデフォルト設定をレコード・モードに変更したり, "ctx=stm" を指定することでストリーム・モードに設定することができます。 RMS の相対編成ファイルと索引順編成ファイルは常にレコード・モードでオープンされます。アクセス・モードによって, HP C RTL でのさまざまな I/O 関数の動作が決定されます。
RMS で定義されているファイル・タイプの 1 つに, RMS-11 ストリーム・フォーマット・ファイルがあります。このファイル・タイプは,レコード・フォーマットの FAB$C_STM の値に対応します。このフォーマットは,SYS$GET が各レコードから先頭のヌル・バイトを削除する RMS レコード操作として定義されています。このファイル・タイプは HP C RTL によってレコード・モードで処理されるため,明示的に "ctx=stm" を指定してオープンしない限り,バイナリ・データのファイル・フォーマットとしては不適切です。 "ctx=stm" を指定した場合は,ファイルのデータ・バイトがそのまま返されます。
OpenVMS バージョン 7.0 で,ストリーム・ファイルの LRL のデフォルト値は 0 から 32767 に変更されました。この変更により,ソートなどの特定のファイル操作で性能が著しく低下しました。 しかし,この問題は回避することができます。 HP C RTL では,論理名 DECC$DEFAULT_LRL を定義することで,ストリーム・ファイルのレコード長のデフォルト値を変更できるようになりました。 HP C RTL は最初にこの論理名を検索します。この論理名が検索され,0〜32767 の範囲の数値に変換されると,その値がデフォルト LRL として使用されます。 OpenVMS バージョン 7.0 より前の動作に戻すには,次のコマンドを入力します。
|
RMS ファイルへのストリーム・アクセスは, RMS のブロック I/O 機能を使用して実行されます。 RMS ファイルからのストリーム入力は,ディスクに格納されているファイルの各バイトをプログラムに渡すことにより実行されます。 RMS ファイルへのストリーム出力は,プログラムからファイルに各バイトを渡すことにより実行されます。 HP C RTL はデータに対して特殊な処理を何も実行しません。
ファイルをストリーム・モードでオープンすると, HP C RTL は大きな内部バッファ領域を割り当てます。データは単一読み込みを使用してファイルからバッファ領域に読み込まれ,必要に応じてプログラムに渡されます。内部バッファが満杯になるか,または
fflush関数が呼び出されると,データはファイルに書き込まれます。
1.8.2.2 レコード・モードでの RMS レコード・ファイルへのアクセス
レコード・ファイルへのレコード・アクセスは, RMS のレコード I/O 機能を使用して実行されます。 HP C RTL は,レコードの読み込み処理と書き込み処理でキャリッジ制御文字を変換することにより,バイト・ストリームをエミュレートします。すべてのレコード・ファイルに対してランダム・アクセスが可能ですが, VFC ファイル,可変長レコード・ファイル,ヌル以外のキャリッジ制御付きファイルの場合,位置設定 ( fseekおよび lseek) はレコード境界で行う必要があります。レコード・ファイルの位置設定を行うと,バッファに格納されているすべての入力が破棄され,バッファに格納されている出力はファイルに書き込まれます。
RMS レコード・ファイルからのレコード入力は,次の 2 つのステップで HP C RTL によってエミュレートされます。
RMS の用語で表現すると, HP C RTL は次のいずれかの方法を使用して,レコードのキャリッジ制御情報を変換します。
ファイルから読み込む場合, HP C RTL は変換から作成されたバイト・ストリームを渡します。 1 回の関数呼び出しで拡張されたレコードから読み込まれなかった情報は,次回の入力関数呼び出しで渡されます。
HP C RTL は RMS レコード・ファイルに対するレコード出力を次の 2 つのステップで実行します。
レコード出力エミュレーションの最初の部分は,論理レコードの作成です。データ・バイトをレコード・ファイルに書き込む場合,エミュレータは書き込む情報からレコード境界を調べます。バイト・ストリームでの情報の処理は,次に示すように,出力先のファイルやデバイスの属性に応じて異なります。
レコード出力エミュレーションの 2 番目の部分では,最初のステップで作成した論理レコードを書き込みます。 HP C RTL は出力レコードを次のように作成します。
1.8.2.2.1 レコード・モードでの可変長または VFC レコード・ファイルへのアクセス
レコード・モードで可変長または VFC レコード・ファイルにアクセスする場合,多くの I/O 関数がストリーム・モードの場合と異なる動作をします。ここでは,これらの相違点について説明します。
一般に,どのレコード・モードでも改行文字 (\n) がレコード区切り文字として使用されます。出力時には,改行文字が検出されると,改行の解釈に影響を与える省略可能な引数 (たとえば "ctx=bin" や "ctx=xplct" など) を指定していない限り,レコードが作成されます。
read関数と decc$record_read関数は常に最大 1 つのレコードを読み込みます。 write関数と decc$record_write関数は常に少なくとも 1 つのレコードを作成します。
decc$record_read関数は read関数に対応し, decc$record_write関数は write関数に対応します。ただし,これらの関数はファイル記述子ではなく,ファイル・ポインタを操作する点が異なります。
read関数は最大 1 つのレコードを読み込みますが, fread関数では複数のレコードにわたる読み込みが可能です。 fread関数は,number_items によって指定される数のレコードを読み込むのではなく (number_items は freadの 3 番目のパラメータ), number_items x size_of_item に等しいバイト数を読み込もうとします (size_of_item は freadの 2 番目のパラメータ)。 freadから返される値は,読み込んだバイト数を size_of_item で除算した値に等しくなります。
fwrite関数は常に少なくとも number_items で指定される数のレコードを作成します。
fgets関数と gets関数は改行文字またはレコード境界まで読み込みます。
バッファに書き込まなければならないデータがある場合, fflush関数は常にレコードを生成します。 close, fclose, fseek, lseek, rewind, fsetposの場合も同様で,これらの関数はすべて,暗黙に fflush関数を実行します。
最大レコード・サイズに指定されている文字より多くの文字を書き込もうとした場合も,レコードが生成されます。
これらの関数の詳細については,『HP C ランタイム・ライブラリ・リファレンス・マニュアル (下巻)』「リファレンス・セクション」を参照してください。
1.8.2.2.2 レコード・モードでの固定長レコード・ファイルへのアクセス
レコード・モードで固定長レコード・ファイルにアクセスする場合, I/O 関数は一般に, 第 1.8.2.2.1 項 で説明したように動作します。
省略可能な引数 "ctx=xplct" を指定してファイルをオープンした場合を除き,指定したレコード・サイズが最大レコード・サイズの整数倍でないと, write関数, fwrite関数, decc$record_write関数はエラーになります。他のすべての出力関数は n バイトごとにレコードを生成します。ただし,n は最大レコード・サイズです。
fflushによって新しいレコードが生成される場合,最大レコード・サイズになるようにバッファ内のデータにヌル文字が付加されます。
ファイルの終端 (EOF) を検索するプログラムの場合,このヌル文字の付加が問題になることがあります。たとえば,プログラムでファイルの終端にデータを追加した後,ファイルを逆向きにシークし ( fflushが実行されます),その後で再びファイルの終端を検索すると,元のファイルの終端がレコード境界上になかった場合,元のファイルの終端と新しいファイルの終端の間に, 0 が埋め込まれた「穴」が作成されています。 |
例 1-1 は,ストリーム・モードとレコード・モードのアクセスの相違点を示しています。
例 1-1 ストリーム・モードとレコード・モードのアクセスの相違点 |
---|
/* CHAP_1_STREAM_RECORD.C */ /* This program demonstrates the difference between */ /* record mode and stream mode input/output. */ #include <stdio.h> #include <stdlib.h> #include <string.h> void process_records(const char *fspec, FILE * fp); main() { FILE *fp; fp = fopen("example-fixed.dat", "w", "rfm=fix", "mrs=40", "rat=none"); if (fp == NULL) { perror("example-fixed"); exit(EXIT_FAILURE); } printf("Record mode\n"); process_records("example-fixed.dat", fp); fclose(fp); printf("\nStream mode\n"); fp = fopen("example-streamlf.dat", "w"); if (fp == NULL) { perror("example-streamlf"); exit(EXIT_FAILURE); } process_records("example-streamlf.dat", fp); fclose(fp); } void process_records(const char *fspec, FILE * fp) { int i, sts; char buffer[40]; /* Write records of all 1's, all 2's and all 3's */ for (i = 0; i < 3; i++) { memset(buffer, '1' + i, 40); sts = fwrite(buffer, 40, 1, fp); if (sts != 1) { perror("fwrite"); exit(EXIT_FAILURE); } } /* Rewind the file and write 10 characters of A's, then 10 B's, */ /* then 10 C's. */ /* */ /* For stream mode, each fwrite call outputs 10 characters */ /* and advances the file position 10 characters */ /* characters. */ /* */ /* For record mode, each fwrite merges the 10 characters into */ /* the existing 40-character record, updates the record and */ /* advances the file position 40 characters to the next record. */ rewind(fp); for (i = 0; i < 3; i++) { memset(buffer, 'A' + i, 10); sts = fwrite(buffer, 10, 1, fp); if (sts != 1) { perror("fwrite2"); exit(EXIT_FAILURE); } } /* Now reopen the file and output the records. */ fclose(fp); fp = fopen(fspec, "r"); for (i = 0; i < 3; i++) { sts = fread(buffer, 40, 1, fp); if (sts != 1) perror("fread"); printf("%.40s\n", buffer); } return; } |
このプログラムを実行すると,次の出力が生成されます。
Record Mode AAAAAAAAAA111111111111111111111111111111 BBBBBBBBBB222222222222222222222222222222 CCCCCCCCCC333333333333333333333333333333 Stream mode AAAAAAAAAABBBBBBBBBBCCCCCCCCCC1111111111 2222222222222222222222222222222222222222 3333333333333333333333333333333333333333 |
前へ | 次へ | 目次 | 索引 |