ファイル読み込みが上手くできません

このQ&Aのポイント
  • C言語初心者の質問者は、大きなファイルを読み込んで処理するプログラムを作成していますが、最後の1回のループでファイルポインタが進まない問題に遭遇しています。
  • 質問者は、ファイルを構造体に格納し、400000行ごとに読み込んで処理を実行していますが、最後の1回のループだけファイルポインタが進んでいない状況です。
  • コードを確認したところ、最後のループ内のwhile文で、ループ変数iの増加がないため、ファイルポインタが進まないことが分かりました。ループ内でiを増加させるように修正すると問題が解決するはずです。
回答を見る
  • ベストアンサー

ファイル読み込みが上手くできません

C言語初心者です。 現在、ファイルの情報を構造体に読込んで実行するプログラムを作成しております。 読込むファイルは700MBほど(行数は39900000行)となっており、1行ずつfscanfで読込んでいます。 400000行ごとに構造体に読込んで、処理を実行し、構造体に読込んだ全ての処理が完了したら、再度400000行読込んで・・・を繰り返すものになっております。 400000行ごとにしているためforループで100回まわすようにしているのですが、最後の1回(100回目のループ)で、99回目と同じ場所を読んできてしまいます。 つまり、最後の1回だけはファイルポインタが進んでいない状況になります。 コードは下記になります。 #define MAX_SIZE 400000 uint64_t i = 0; uint64_t fc = 0; int main(int argc, char *argv[]){ char w[] = "$write"; char r[] = "$read"; // ファイルを構造体へ格納 char filename[] = "TEST_READ_WRITE.txt"; struct TEST_DATA{ char cmd[10]; int addr; int bsize; }; FILE *fp; if ((fp = fopen(filename, "r")) == NULL){ printf("%s open error !\n", filename); exit(1); } for (int lp = 0; lp < 100; lp++){ struct TEST_DATA TD[MAX_SIZE]; // 構造体配列の宣言 for (fc = 0; fc < MAX_SIZE; fc++) { if (feof(fp)){ break; } else{ fscanf(fp, "%s %d %d\n", TD[fc].cmd, &TD[fc].addr, &TD[fc].bsize); } } while (i < MAX_SIZE - 1){ //ファイルから取得したデータによって処理を実行 if (strcmp(TD[i].cmd, w) == 0){ //書込み処理 } if (strcmp(TD[i].cmd, r) == 0){ //読み込み処理 } } printf("Finish!! \n"); } fclose(fp); return 0; } 読込むファイルはテキストデータで、 $write 25651496 152 $write 135878112 8 $read 1244848 16 のような感じのものが39900000行並んでいるものになります(数字はランダムです)。 最後の1回のみ上手くファイルポインタが進まない原因が分からずに困っています。 お気づきの方がいらっしゃいましたら、アドバイスをよろしくお願いします。

  • sgurk
  • お礼率50% (3/6)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

iの初期化とカウントアップは正しく処理されているという前提で。 ファイルポインタが進まないのではなくて、ファイル終端に達した場合の処理が正しくないのでは? if (feof(fp)){ break; } でfcをループカウンタとしたforループから抜けていますが、iを使ったwhileループでは、どこまでデータが読み込まれたか確認せずにMAX_SIZE-1までループしてますよね。 たとえばfc=0の時にfeof(fp)がtrueになったとして、そのあとのwhileループはMAX_SIZE-1回処理されてしまうので、一回前の処理で読み込まれたTDに対して処理を行い、結果ファイルポインタが進んでないように見えるということになりませんか? fcの上限がMAX_SIZEで、iの上限がMAX_SIZE-1というのもおかしいと思います。

sgurk
質問者

お礼

m-take0220さん 返信が遅くなり、申し訳ございません。 ご回答、ありがとうございました。 前の回答でmaiko0318さんもおっしゃっていたようにカウント処理が間違っていました。 最後のループだけ実行されていないように見えていましたが、実際は構造体に入れている値の MAX値が400000としていたため、ファイルの最大行数を越えた部分だけが前のデータで 使用されているようでした。 カウンタの値を変更したところ、目的の動作を行っています。 アドバイス、ありがとうございました。

その他の回答 (1)

  • maiko0318
  • ベストアンサー率21% (1483/6970)
回答No.1

while (i < MAX_SIZE - 1){ 読んだ件数をカウントして処理しないと、 構造体に残っている前のデータが処理されてしまっている。 fcを使いましょう。

sgurk
質問者

補足

maiko0318さん ご回答ありがとうございます。 今更ですが、貼り付けたコードにミスがありました。 while ループを抜けたときにi=0をしているのですが、記載したコードでは抜けていました。 申し訳ございません。 読んだ件数をカウントして処理するというのは、MAX_SIZEの代わりにfcを使用するということでしょうか? 現状、構造体の中身はwhileループで処理をした後のforループ内で上書きしていると思っていました。 実際に最後の1回以外は予定通り構造体の中身が更新されているように見えていたのですが、fcを使わないと上手く処理できないようですので、修正してみます。

関連するQ&A

  • テキストデータから構造体にデータを保存する方法

    C言語初心者です。 大きなテキストデータ(730MB)からデータを取得して、構造体に保存し表示するというプログラムを作成しています。テキストのサイズが大きいため構造体のサイズを400000とし、 残りをftellとfseekを使用してファイルポインタをずらして全データを順次読み込んで表示しようとしているのですが、実行すると400000行目以降(最初の構造体のMAX時点)がうまく読み込めません。 詳しい方がいましたら、ご教授願います。 #define MAX_SIZE 400000 char filename[] = ″test.txt"; struct ALL_DATA{ char cmd[10]; int addr; int bsize; }; for (int lp = 0; lp < 100; lp++){ FILE *fp; struct ALL_DATA ADATA[MAX_SIZE]; // 構造体配列の宣言 if (lp > 0){ fseek(fp, LP, SEEK_SET); } if ((fp = fopen(filename, "r")) == NULL){ printf("%s open error !\n", filename); exit(1); } for (fc = 0; fc < MAX_SIZE; fc++) { if (feof(fp)){ break; } else{ fscanf(fp, "%s %d %d\n", ADATA[fc].cmd, &ADATA[fc].addr, &ADATA[fc].bsize); } } LP = ftell(fp); //現在のFPの取得 printf("********** FP-> %ld *********\n", LP); fclose(fp); while (i < MAX_SIZE){ if (loopcnt == 0){ printf("ADATA[i].cmd -> %s, ADATA[i].addr -> %d, ADATA[i].bsize -> %s\n",ADATA[i].cmd, ADATA[i].addr, ADATA[i].bsize); // i++; } } 上記のような形で作成しています(一部抜粋)。 読み込むテキストデータは testA 123456 20 testA 23415 2 testB 12114567 678 のように「文字列 スペース 数字 スペース 数字」と並んでおり 値はランダムになっています。 初めて質問するため、わかりにくい記述があるかと思いますが、よろしくお願いします。

  • csvファイルを構造体に読み込みたい

    C言語初心者です。 csvファイルのデータを1行ずつ構造体に読み込みたいのですが、うまくできません。 #define MAX_SIZE 100 char filename[] = ″test.csv"; struct ALL_DATA{ int cnt; char list[10]; char addr[10]; char cmd[10]; char csize[10]; char input[10]; char icmd[10]; char input2[10]; }; for (int lp = 0; lp < 10; lp++){ FILE *fp; struct ALL_DATA ADATA[MAX_SIZE]; // 構造体配列の宣言 if ((fp = fopen(filename, "r")) == NULL){ printf("%s open error !\n", filename); exit(1); } for (fc = 0; fc < MAX_SIZE; fc++) { if (feof(fp)){ break; } else{ fscanf(fp, "%d,%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],\n", &ADATA[fc].cnt, ADATA[fc].list, ADATA[fc].addr,ADATA[fc].cmd,ADATA[fc].csize,ADATA[fc].input,ADATA[fc].icmd,ADATA[fc].input2); } } fclose(fp); while (i < MAX_SIZE){ printf("ADATA[i].cnt -> %d, ADATA[i].list -> %s, ADATA[i].addr -> %s, ADATA[i].cmd -> %s, ADATA[i].csize -> %s, ADATA[i].input -> %s, ADATA[i].icmd -> %s, ADATA[i].input2 -> %s\n",ADATA[fc].cnt, ADATA[fc].list,ADATA[fc].addr,ADATA[fc].cmd,ADATA[fc].csize,ADATA[fc].input,ADATA[fc].icmd,ADATA[fc].input2); i++; } } 読み込みたいcsvデータは 1 test 0x0012 write 0x001 yes 0xabc yes 2 testa 0x00cd read 0x024 0x1a3 のように、「数字、文字列・・・」と並んでいます。 このデータを取り込んで表示させたところ、 最初の数字は問題ないのですが、ADATA[i].addr から値がおかしくなり、 ADATA[i].addr = 0x0012write ADATA[i].cmd = write ADATA[fc].csize = 0x001yes のように、16進数を文字列として構造体に入れるときに、次の文字(英字)まで一緒に含んでしまう現象が出ております。 ネットで調べて、csvファイルから構造体に取り込む方法はいくつか見たのですが、同じようにしている(と思っている)のにうまくいかないため、質問させていただきました。 原因がわかる方がいらっしゃいましたら、アドバイスをよろしくお願いいたします。

  • ファイルの読み込みとメモリ確保について。

    ファイルから文字を読み込んで それを配列に入れて辞書順にソートさせようとしています。 それで、ソート以前の問題なのですが、ファイルから文字列を読み込んで配列にいれようとするのですが、 buffを動的にメモリ確保してその配列に入れたいと考えているのですが、なぜか入ってくれません。 whileでファイルの終わりがくるまで一行ずつ読み込んで それをsに入れていき、sをbuff[]の配列に順番にいれていこうとしているのですが・・・。 ファイルは aaaa aabc dda wer zie ced sdfe be など適当な文字の並びです。 malloc関数で動的に確保したメモリはその後普通の配列と同様に使えるのではなかったのでしょうか? なので普通にbuff[i]=s;といった処理で入れれると思ったのですが。 ファイルは一行の長さの最大が100で 行数が4000行あると仮定しています。 今は小さいファイルでテストしていますが。 以下ソースです。 #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 #define MAX_LINE 4000 main() { FILE *fp; char *buff,s[MAX_SIZE]; int i; fp=fopen("words.txt","r"); buff=(char*)malloc(sizeof(char)*MAX_LINE); i=0; while(fgets(s,MAX_SIZE-1,fp)!=NULL){ buff[i]=s; printf("%s",buff[i]); i++; } fclose(fp); } とりあえずファイルの内容を配列に入れないとソートできないので、配列に全て入れてしまいたいと考えています。 間違いがどこにあるのか指摘よろしくおねがいします。m(-_-)m

  • ファイルポインタfpを、何バイト読んだかカウンタとして使うには?

    ファイルポインタfpを、何バイト読んだかカウンタとして使うには?どうしたら良いか教えてください。binary fileをオープンして、1Byteずつc=fgetc(fp); を繰り返し読込み特定の処理します。数百万バイトを読んだあたりで、こけるので、何バイト目あたりでこけているのか知りたいというのが動機です。 fp構造体の中で、今、ファイルの冒頭から何バイト読んだところ、という情報を引っ張り出して1Byte読み込むごとに(ずらずらとでいいので)表示したいです。fp->current_byte とかいう情報があるように想像するのですが、どうでしょうか。以下に、#include<stdio.h>の中で、FILE を引用します。 typedef struct { unsigned char *curp; /* Current active pointer */ unsigned char *buffer; /* Data transfer buffer */ int level; /* fill/empty level of buffer */ int bsize; /* Buffer size */ unsigned short istemp; /* Temporary file indicator */ unsigned short flags; /* File status flags */ wchar_t hold; /* Ungetc char if no buffer */ char fd; /* File descriptor */ unsigned char token; /* Used for validity checking */ } FILE; /* This is the FILE object */

  • ファイル操作

    あるファイルから長さの違った数字や文字を読み込んで配列に格納したいのですが数字などの長さが違うとなんかおかしくなってしまいます; 例えば 1 a 1 2 a 2 3 b 3 4 b 4 などのファイルはできるのですが 0 1 2 3 a 3 4 b 4 5 c 5 の場合5つの配列に格納したいのです。1行目で1つ2行目で1つ3行目の 左、真ん中、右の数字でそれぞれ1つづつ格納したいのです。 それで自分でやったのですが typedef struct path{ int left [100]; int right[100]; char center [100]; }Path; int main(int argc,char *argv[]) { FILE *fp; Path path; int i=0; int first; int second[100]; fp = fopen(argv[1],"r"); while(fscanf(fp,"%d %c %d",&path.left[i],&path.center[i],&path.right[i])==3){ i++; } fclose(fp); このようにやると3行目からはきちんとよみこむのですが1、2行目がうまくできません@@; firstとsecondのそれぞれ1、2行目を入れたいのです。 fscanfをもう1つ増やすしてもやってみましたがうまくいきませんでした。 ちなみにfscanf関数のところをならったばかりです。 fgetcとかそのようなのを使うのでしょうか?(よくわからないですけど) よろしくお願いします。ちなみにLinuxでgcc、C言語です。

  • ファイルの読み込み

    以下のデータが入ったファイルを読み込んで、出力するプログラムを 作成したのですが、旨くデータを出力できません。どなたか教えていただけないでしょうか?  E | 1 3 | 1 E | 2 | 1 2 E | 3 | 0 E | E | 0 #include<stdio.h> #include<string.h> #include<stdlib.h> #define NFA_STATE_MAX 128 typedef struct nlist{ int c; int to; int from; }nlist_t; main() { char line[255]; FILE *fp; int i,j; if((fp = fopen("data.txt", "r")) == NULL) { printf("Can't Open This File.?n"); exit(1); } char atranbysymbol[100]; char *tranofsymbol; int ntran = 0; int nstate=4, nsymbol=2; nlist_t nfa[NFA_STATE_MAX]; for(i=0; i<nstate; i++) { int ns = 0; fgets(line,255,fp); tranofsymbol = strtok(line,"|"); while(tranofsymbol != NULL) { atranbysymbol[ns++] = *tranofsymbol; tranofsymbol = strtok(NULL,"|"); } for(j=0; j<=nsymbol;j++) { char *sto; strcpy(line, &atranbysymbol[j]); sto = strtok(line," "); while(sto != NULL) { if(strcmp(sto, "E")!= 0) { nfa[ntran].to = atoi(sto); nfa[ntran].from = i; nfa[ntran++].c = j - 1; } sto = strtok(NULL, " "); } } } for(i=0; i<ntran; i++) { printf("From: %d ", nfa[i].from); printf("To: %d ", nfa[i].to); printf("on Symbol: %d ?n", nfa[i].c); } return 0; }

  • ファイルから読みこんで構造体に格納する、

    shohinというファイルに RX-100 odango_tsumeawase 3000という のが 五行ならんでいるのですが、 これを読み込んで struct shohin{ char code[10]: char name[40]; int price; } にファイルから読みこんで構造体配列に 格納したいのですが、構造体配列に格納する やりかたがわかりません。 構造体配列は struct shohin list[];というのを宣言しています。 ファイルから一行読み込んで fprintf()を使おうと思うのですが、 それはできますか? メンバ毎に格納したいのですが、 それがわかりません お願いします。

  • ファイルの読み込みと構造体

    こんばんは☆ Cのプログラミングに困っています(>_<) テキストファイル(meibo.txt) 田中 32 公務員 佐藤 20 学生 というファイルを読み込んで、構造体に入れて表示するには どうしたらよいでしょうか? struct meibo{     char name[20];     int age;     char job[20]; }list[3]; としたあとにどのように入れたらよいかがわかりません… わかる方教えてくださいm(_ _)m

  • ファイルを読み込むプログラムについて

    下のプログラムで分からない所がありますので、教えて頂ければと思います。宜しくお願い致します。 text = fgets(buf,256,fp);はfpのファイルから一行を読み込んでbufに格納するという処理ということは分かります。でも、while文内なので次にこの処理をする時に今度は、2行目(下の段)を読み込むはずですが、プログラム中のどこに2行目に移動させる処理があるのか分かりません。 予想ですが、text = fgets(buf,256,fp);の中にそのような意味の処理が含まれているのでしょうか? どなたかご教授お願い致します。 #include <stdio.h> int main(void) { FILE *fp; char buf[256]; char *text; char flname[256]; printf("ファイル名:"); gets(flname); fp = fopen(flname,"r"); do{ text = fgets(buf,256,fp); if(text != NULL){ printf("%s",text); } }while(text != NULL); fclose(fp); return(0); }

  • csvファイルの読み込みで失敗します

    以下のようなソースでカンマ区切りのテキストファイルであるcsvファイルの行数、列数、要素数を取得するプログラムを作っているのですが、終わりのメモリ解放であるdelete []strのところでプログラムが落ちてしまいます。範囲外のメモリにアクセスしてしまっているのかと思いますが、ミスを特定できないので、教えてください。 読み込むcsvファイルには以下のような小数の値が入っています。 0.23960810421811729043, 11.753428210139766463, …(省略) , 3.8736893050771881164 int main( int argc, char **argv ) { int csvRowNum, csvColNum, csvElemNum; GetCSVDataNum ( "C:\\Data.csv", csvRowNum, csvColNum, csvElemNum ); return 0; } // csvファイルから行数、列数、要素数を取得する int GetCSVDataNum ( char *csv_name, int &rowNum, int &colNum, int &elemNum ) { FILE *fp; fp = fopen( csv_name, "r" ); if( fp == NULL ){ printf( "ファイルオープンエラー\n" ); exit(1); } // ファイルサイズの取得 int fsize; fseek( fp, 0L, SEEK_END ); fsize = ftell( fp ); // ファイルシーク位置を先頭に戻す fseek( fp, 0L, SEEK_SET ); // ファイルサイズに合わせて文字列領域確保 char *str; str = new char[fsize]; char buf[10000]; // ファイルから1行ずつテキストデータを読み込み、 // 連結してbufに格納する str[0] = '\0'; while ( fgets( buf, sizeof(buf), fp ) != NULL ) { strncat( str, buf, strlen(buf) ); } int countSep = 0; // '(カンマ)の数のカウント int cols = 0; // 各行の列数をカウント int countNL = 0; // 改行の数をカウント // 要素数、行数、列数の取得 for ( int i = 0; i < (int)strlen(str); i++ ) { switch( str[i]){ case ',': countSep++; cols++; break; case '\n': countNL++; cols++; // 各行で列数が異なるときは、最も大きい列数とする colNum = (colNum > cols ) ? colNum: cols; cols = 0; break; default: break; } } rowNum = countNL; elemNum = countSep + countNL; // strの解放で落ちる delete[] str; fclose( fp ); return 0; }