ランダムアクセス


ファイルの先頭から順番に読み書きすることをシーケンシャルアクセスといいます。ファイルの任意の場所から読み書きできると、より実用的なプログラムを作ることができます。ファイルの任意の位置にアクセスすることをランダムアクセス(random access)といいます。

これは、fseek 関数を使えば比較的簡単に実現できます。f で始まる関数なのでファイル関連の関数あと推理できますね。seek は英語で「探す」という意味です。

int fseek(
          FILE *stream,
          long offset,
          int origin                                                                      
          );

stream には FILE 構造体へのポインタを指定します。offset には、origin からのバイト数を指定します。origin には、初期位置を指定します。数値で指定してもよいのですが、次の定数を指定することもできます。

origin に指定する定数

しかし、テキストモードで開いたファイルは改行の変換によっておかしな結果となることもあります。テキストモードでも正しく動作するのは origin が SEEK_SET のときと覚えておきましょう。

それでは、もっとも簡単な例を示します。今まで使ってきた text.txt をランダムに読込んでみましょう。その前に、このファイルに書込まれている形式をもう一度確認してみましょう。

1人分のデータは "%-15s %-15s\n"の変換指定子で書込まれています。「名前15バイト+電話番号15バイト+改行文字(CR-LF)2バイト」です。

つまり、1人分のデータは33バイトです。n番目の人のデータはファイルの先頭から33×(n-1)バイト目からということになります(ファイルの先頭は0バイト目)

ソースコード

源文件

  1|/* random01.c */
  2|
  3|#include <stdio.h>
  4|#include <stdlib.h>
  5|#include <string.h>
  6|
  7|#define RECORDLEN 33
  8|
  9|int main(void)
 10|{
 11|  FILE *fp;
 12|  char fname[256], data[16], ans[8];
 13|  int no;
 14|
 15|  printf("ファイル名(拡張子不要)--");
 16|  scanf("%s", fname);
 17|  fp = fopen(strcat (fname, ".txt"), "r");
 18|if(fp == NULL){                                                                       
 19|  perror("ファイルがオープンできません\n");
 20|  return -1;
 21| }
 22|
 23|while(1){
 24|  printf("何人目のデータを読込みますか--");
 25|  scanf("%s", ans);                                                                   
 26|  no = atoi(ans);
 27|  fseek(fp, RECORDLEN * (no - 1), SEEK_SET);
 28|  if(fscanf(fp, "%s", data) == EOF) {
 29|    perror("読込みエラーです\n");
 30|    continue;
 31|  }
 32|  printf("[氏名] %s", data);
 33|  fscanf(fp, "%s", data);
 34|  printf("[電話] %s\n", data);
 35|  printf("続けますか(y/n):");
 36|  scanf("%s", ans);
 37|  if(strcmp (ans, "n") == 0 || strcmp (ans, "N") == 0){
 38|    break;
 39|  }
 40| }
 41|fclose(fp);
 42|return 0;
 43|}

実行結果

ファイル名(拡張子不要)--text
何人目のデータを読込みますか--1
[氏名] 河野[電話] 080-1234-5678
続けますか(y/n):y
何人目のデータを読込みますか--10
読込みエラーです
: Undefined error: 0
何人目のデータを読込みますか--2
[氏名] 山田[電話] 080-9999-0120
続けますか(y/n):n

fseek 関数はファイルの終端を超えた場所を指定してもエラーとはなりません。しかし、fscanf 関数は読込みに失敗して EOF を返します。上の例では3回目にわざと、10人目という存在しないデータを要求してみました。



ソースコード

源文件
  1|/* random02.c */
  2|
  3|#include <stdio.h>
  4|#include <string.h>
  5|#include <stdlib.h>
  6|
  7|#define FNAME "meibo.txt"
  8|#define RECORDLEN 88
  9|
 10|int menu();
 11|int myread();
 12|int mywrite();
 13|int myrewrite();
 14|
 15|char *format = "%-15s %-3d %-2 %-63s\n";
 16|
 17|int main(void)
 18|{                                                                                     
 19|  int menuno;
 20|  while(1){
 21|    menuno = menu();
 22|    switch (menuno){
 23|    case 0:
 24|      break;
 25|    case 1:                                                                           
 26|      mywrite();
 27|      break;
 28|    case 2:
 29|      myread();
 30|      break;
 31|    case 3:
 32|      myrewrite();
 33|      break;
 34|    default:
 35|      printf("不正です\n");
 36|      break;
 37|    }
 38|    if(!menuno){
 39|      break;
 40|    }
 41|  }
 42|  return 0;
 43|}
 44|
 45|int menu()                                                                            
 46|{
 47|  char ret[8];
 48|
 49|  while(1){
 50|    printf("*************************\n");
 51|    printf("1:データ書込み(新規•追加)\n");
 52|    printf("2:データ読み出し\n");
 53|    printf("3:データ修正\n");
 54|    printf("0:終了\n");
 55|    printf("*************************\n");
 56|    printf("選択-->");
 57|    scanf("%s", ret);
 58|    ret[1] = '\n';
 59|    if(ret[0] < '0' || ret[0] > '3') {
 60|      printf("番号が不正です\an>"keyword">return -1;
 78|  }
 79|  while(1){
 80|    printf("氏名--");
 81|    scanf("%s", name);
 82|    printf("年齢--");
 83|    scanf(90|    if(fprintf(fp, format, name, age, sex, address) < 0){
 91|      perror("書込むエラーが発生しました");
 92|      break;
 93|    }
 94|    printf("さらに入力を続けますか(y/n):");
 95|    scanf("%s", buffer);
 96|    if(buffer[0] == return 0;
102|}
103|
104|
105|int myread()                                                                          
106|pan>|    perror("ファイルをオープンできません\n");
114|    return -1;
115|  }
116|  printf("検索する氏名--");
117|  scanf("%s", search);
118|
119|  while(1) {
120|    fseek(fp, RECORDLEN *s="string">"%d", &age);                                                         
126|      fscanf(fp, "%s", sex);
127|      fscanf(fp, "%s", address);
128|      printf("氏名: %s\n", name);
129|      printf("年齢: %d\n", age);
130(yesno[0] == 'y' || yesno[0] == 'Y'){
136|        continue;
137|      } else {
138|        break;
139|      }
140|    }
141|  }
142|  printf("%d件が検索されました\n", finpan class="number">149|  FILE *fp;
150|  char buffer[8], shusei[16], yesno[8],
151|    name[16], sex[4], address[64"修正するデータの氏名--");
160|  scanf("%s", shusei);
161|
162|  while(1){
163|    fseek(fp, RECORDLEN * no++, SEEK_SET);
164|    171|      fscanf(fp, "%s", address);
172|      printf("氏名: %s\n", name);
173|      printf("年齢: %d\n", age);
174|      printf("性別: %s\n", sex);
175|      printf(180|        printf("氏名を修正いますか(Y/N):");
181|        scanf("%s", yesno);
182|        if(yesno[0] == 'y' || yesno[0] == 'Y') {
183|          printf("氏名--== 'y' || yesno[0] == 'Y'){
189|          printf("年齢--");
190|          scanf("%s", buffer);
191|          age = atoi(buffer);
192|        }
193|        printf("性別を修正しますか(Y/N):");
194|        scanf("%s", yesno);
195|        if(yesno[pan>|        }
199|        printf("住所を修正しますか(Y/N):");
200|        scanf("%s", yesno);
201|        if(yesno[0] == 'y' || yesno[0] == 'Y'){
202|          prinber">210|  if(find == 0){
211|    printf("修正すべきデータはありませんでした\n");
212|  }
213|  fclose(fp);
214|  return 0;
215|}

実行結果


Chapte9 @ C言語目録 @ HomeWork List @ 昭亮's Homepage