サイトマップ / C言語講座>出入り口>総目次>目次:ファイル>ランダムアクセスファイル
[ユニークなファイル名で開く]←このソース→[空白文字の出現頻度]
/* 今日は、レコードの長さが一定の多数のデータを、書き込み用に開いたファイルに出力し、そのファイルを入力用として再度開き、レコード番号を入力して、その内容を画面に表示させます。つまり、ランダムアクセスファイルを作製し、データへのランダムアクセスを行います。ランダムアクセスを行うには、データの長さが一定の方が、容易です。
fseek( ) は、ファイルポインタで示されるファイル内で、次に読み込みあるいは書き込みを始める場所 ( ストリーム ) を指定します。
#include <stdio.h> int fseek(FILE *fp, long int offset, int where); 例:err = fseek(fp, offset, where); 実行結果 戻り値 成功 0 失敗 0 以外の数
where で、次に読み込みあるいは書き込みを始める場所を指定します。
SEEK_SET ファイルの先頭から SEEK_CUR 現在の位置から SEEK_END ファイルの最後から
上記の値は <stdio.h> の中で定義されています。offset には、where で指定した位置からの距離をバイト単位で指定します。
freopen( ) は、filename で指定されたファイルを開きます。fopen( ) に似ていますが、もし、指定のファイルが開いていたら、一旦閉じてから、開きます。mode の指定の仕方は、fopen( ) と同じです。
#include <stdio.h> FILE *freopen(const char *filename, const char *mode, FILE *fp); 例:newfp = freopen(filename, mode, oldfp); 実行結果 戻り値 成功 filename へのファイルポインタ 失敗 NULL
今回のソースプログラムでは、"w" モード ( 新しいテキストファイルを出力モードで開く ) を、"r" ( テキストファイルを入力モードで開く ) に変更しています。
今回使っている乱数のシードを設定する関数 SetSeed( ) と、乱数を発生する関数 GetRand( ) につきましては、このファイル を参照して下さい。ただし、 GetRand( ) は少し改造してあり、最大値で、引数 max までの正の整数を返す点が異なっています。
メインルーチンの中で、長さ LEN_ITEM_NAME の無意味なアルファベットの文字列を作り、それを name[ ] にしまいます。
name[j] = 'a' + GetRand(26);
上記のコードにより、name[ ] の j 番目の要素に、'a' から 'z' のどれかの文字が入ります。26 はアルファベットの文字数です。レコード番号と、上記の無意味な文字列と、0 から MAX_PRISE までのint 型の乱数 prise を、一つのレコードとしてファイルに書き込みます。書き込むデータの総数は MAX_ITEM 個です。書き込みに使う書式文字列は、読み込みにも使います。
最後に入力モードでファイルをリオープンし、レコードにレコード番号でランダムアクセスし、レコードの内容を表示します。数字以外を入力するとループから抜けます。 */
#include <stdio.h> #include <time.h> /* clock( ) で必要 */ #include <stdlib.h> /* exit( ) で必要 */ #define MUL 12345 /* 乱数の発生に使用 */ #define INC 54321 #define MOD 65535 #define LEN_ITEM_NAME 2 /* 無意味な文字列の長さ */ #define MAX_PRISE 1000 /* 乱数の最大値 */ #define MAX_ITEM 60 /* ファイルに書き込むレコードの数 */ #define REC_SIZE 30L /* 1 レコードのサイズ */ void SetSeed(void); int GetRand(int max); void main(void); static unsigned int seed; /* 乱数のシードを設定 */ void SetSeed(void) { seed = (unsigned int)(clock( ) % MOD ); } /* 最大値 max までの正の乱数を発生させる */ int GetRand(int max) { seed = (MUL * seed + INC) % MOD; return (seed % max); } void main(void) { int number; /* レコード番号 */ char name[LEN_ITEM_NAME]; /* 無意味な文字列をしまう */ int prise; /* 乱数をしまう */ const char *format = "%2d %20s %4d"; /* 書式文字列 */ long n; char *filename = "itemdata.txt"; FILE *fp; int i, j; /* ファイルを出力モードで開く */ if ((fp = fopen(filename, "w")) == NULL) { fprintf(stderr, "ファイルを出力モードで開くのに失敗しました!\n"); exit(2); /* 失敗したらシェルに戻る */ } SetSeed( ); /* 乱数のシードを設定 */ /* MAX_ITEM 個のレコードをファイルに書き込む */ for (i = 0; i < MAX_ITEM; i++) { /* 無意味な文字列を作る */ for (j = 0; j < LEN_ITEM_NAME; j++) name[j] = 'a' + GetRand(26); /* 26 はアルファベットの文字数 */ name[LEN_ITEM_NAME] = '\0'; /* 末尾にヌル文字を追加 */ prise = GetRand(MAX_PRISE); /* MAX_PRISE までのint 型の乱数 */ fprintf(fp, format, i, name, prise); /* データ書き込み */ } if ((fp = freopen(filename, "r", fp)) == NULL) { /* 入力モードで開く */ fprintf(stderr, "ファイルを入力モードで開くのに失敗しました!\n"); exit(2); /* 失敗したらシェルに戻る */ } printf("レコード番号を入力して下さい ( 0 - %d )?\t", MAX_ITEM - 1); while ( scanf("%ld", &n)) { /* 数字以外の入力でループから抜ける */ if (n < 0 || n > MAX_ITEM - 1) break; /* 不正な値でもループから抜ける */ fseek(fp, n * REC_SIZE, SEEK_SET); /* 読み込む位置を決定 */ fscanf(fp, format, &number, name, &prise); printf("No:%2d Name:%20s Price:%4d", number, name, prise); printf("\nレコード番号を入力して下さい ( 0 - %d )?\t", MAX_ITEM - 1); } fclose(fp); } |
/* while ( ) ループの条件判断の式が、scanf( ) になっています。scanf( ) は変換に成功した変数の数を返すので、数字以外を入力すると 0 を返すので、ループから抜けます。 */
[ユニークなファイル名で開く]←このソース→[空白文字の出現頻度]
/* (C) 2000- YFプロ. All Rights Reserved. */ 提供:C言語講座−それ自体コンパイルできる教材を使った講座です−