• ベストアンサー

fopen(書き込みモード)でファイルが作成されない

Visual StudioでWindowsプログラミングをしています。 RESULT CALLBACK WndProc(HWND hwnd, UINT imsg, WPARAM wp, LPARAM lp){ …  switch(imsg){   case WM_COMMAND:    switch(LOWORD(wp)) {     case ID_FILEOPEN:      FileSet(hwnd);      break;    case ID_WRITE:      if((fp_test=fopen("test_data.dat","w"))==NULL)       exit(0);      fputs("******",fp_test);      fclose(fp_test);      break;   …   }   return 0; } のようにメニューからファイルの読み書きを行わせたいと思っています。 プログラムを実行してすぐにWRITE部分を行うと、 ファイルは正常に作られ、書き込みもできています。 ところが、先にFILEOPENを行うと、その後WRITEが正しく動かず、 ファイル自体が作成されません。 ファイルオープンに失敗すれば、終了するはずですが、それもしません。 FILEOPENで呼び出しているFileSet関数は以下です。 void FileSet(HWND hwnd){//ファイルの選択  char filePath[MAX_PATH];  char fileFolder[MAX_PATH];  char *pt,*ptEnd,*ptEndNext;  if(OpenFiles(hwnd)==1){   pt = FileName;   ptEnd = strchr(FileName,'\0');   ptEndNext = ptEnd + 1;    if(ptEnd){     int nLength;     if(*(ptEndNext) == '\0'){//ファイルが1つしか選択されていない      strcpy( filePath, FileName );      FileOperation(filePath); //ファイルオープンとデータの平滑化    }else{ //複数選択      strcpy( fileFolder, FileName );//フォルダ名の取得      nLength = strlen(fileFolder);      if(fileFolder[nLength]!='\\')       strcat(fileFolder, "\\");      while(*(ptEndNext) != '\0'){       strcpy(filePath, fileFolder); //パス名を作成       strcat(filePath, ptEndNext ); //ファイル名を連結       FileOperation(filePath);       ptEnd = strchr( ptEndNext, '\0' ); //次のファイルを探す       ptEndNext = ptEnd + 1;      }    }   }  } } FileSet関数内で呼んでいるFileOperationは以下です。 テキストデータを数値に変換し、indataという構造体配列に代入しています。 indata,numはグローバル変数です。 void FileOperation(char *filePath, int b){//ファイルオープンとデータスケーリング  int i,j;  double datawork;  char work[10];  if((fp=fopen(filePath,"r"))==NULL)//ファイルオープン   exit(0);  for(i=0,j=0;(i<DATA_NUM) && (fscanf(fp,"%s",work)!=EOF);++i){//データ読み込み   datawork = atof(work);   indata[num].data[j] = (float)datawork/NORM;   j++;  }  fclose(fp);  datawork = 0;  indata[num].number = num;  strcpy(indata[num].fname,filePath);  num++; } おそらくこのあたりに原因があるとは思うのですが、 自分ではわかりませんでした。 お力を貸していただければと思います。 WinXP SP3, VisualStudio 2005で作成しています。 説明不足な部分がありましたらすみません。 よろしくお願いいたします。

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

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

多分関係ありませんが, if(fileFolder[nLength]!='\\')  strcat(fileFolder, "\\"); この処理はおかしいような気がします. 「\ で終わっていれば何もせず, \ で終わっていない場合には \ を付ける」という処理をしたいのだと思いますが, \ で終わっている場合にも \ を付けるのではないでしょうか. 例えば fileFolder が "a" だと nLength は 1 になりますが, fileFolder[nLength] は '\0' ですよね.

asatuge
質問者

お礼

回答ありがとうございました。 ファイルが作れないことに関しては自己解決いたしまして、 FILEOPENした時にカレントディレクトリが変更されていたようで、、 オープンしたファイルのあるディレクトリに、 ファイルはきちんと作成されていました。 書き込みファイル名を絶対パスで指定していなかったことと、 私の早とちりが原因でした。お騒がせいたしました。 ご指摘の部分ですが、確かに変な処理をしていますね…。 実行時に、予期せぬ動作などしなかったので、見過ごしていました。 修正したいと思います。ありがとうございました。

その他の回答 (1)

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.2

Windowsのコールバック関数は、リエントラントである事が要求されます。 しかし、Cの標準ライブラリ関数のfopenは、リエントラント関数である保証はありません。 もし、fopenが非リエントラントで実装されている場合、リエントラントである事が要求される関数内で使用すると、動作は未定義です。 つまり「RESULT CALLBACKと定義されたWndProc関数内では、fopen関数を使用すると、動作は未定義」と言う事です。 リエントラントでない実装のfopen関数をコールバック関数で使用した為、fopenは「予期せぬ動作」をします。それが「どんな動作」かは、誰にも判りません。 今回は「予期せぬ動作」として「ファイルも作らず、何もせず、エラーにもせず、何だか正体の判らないFILEへのポインタを返す」と言う動作をしました。 fopenがリエントラントでない場合については、以下の質問の、当方の回答を参照して下さい。 http://oshiete1.goo.ne.jp/qa4545663.html リエントラントである事が要求されるコールバック関数では、fopenの使用を避けCreateFile(API)を使用するか、fopenに再入しないようミューテックスを設けるなど、工夫が必要です。 ともかく、現状のままでは「fopenは使えない」と思って下さい。

asatuge
質問者

お礼

回答ありがとうございました。 ファイルが作れないことに関しては自己解決いたしまして、 FILEOPENした時にカレントディレクトリが変更されていたようで、、 オープンしたファイルのあるディレクトリに、 ファイルはきちんと作成されていました。 書き込みファイル名を絶対パスで指定していなかったことと、 私の早とちりが原因でした。お騒がせいたしました。 リエントラント関数については、全く知識がありませんでした。 これから勉強したいと思います。 ありがとうございました。

関連するQ&A

  • C言語 fopen

    初心者の質問になります。現在ファイルがオープンできるかどうかを確認したいのですが、指定したディレクトリの中のファイルを指定しているのですが、オープンできませんという結果が返ってきます。同じ場所にファイルを置いてファイル名だけでしていするとオープンが出来ます。 何卒よろしくおねがいします。 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main(void) { FILE *fp; char *filename = "/file/d20151001.csv"; fp = fopen(filename,"r"); if (fp == NULL) { printf("\aファイルをオープンできません\n"); } else { printf("ファイルがオープンできました\n"); fclose(fp); } return (0); } ディレクトリ(わかりにくくてすいません汗) file------d20151001.csv data.c 環境 VisualStudio

  • fopenについて

    ご質問させて頂きます。 ファイルの中身は以下の通りです。 TX55123455846521113456211415122335122200452125442[EOF] という感じの 一行だけの細長いデータです。 このファイルのデータを 読み取ろうとして 以下の様にしました。 int main(void){ char buf[5]; FILE *fp; fp = fopen("ex.fil","r"); if (fp == NULL){ printf("can't open"); exit(1); } エラーは出ないのですが データがないと判断されてしまうようで 「can't open」 となってしまいます。 どういう点がおかしいのか お気づきな点がありましたら ご教示して頂けたら幸いです。

  • fopen関数について

    ----------------------------------------- #include<stdio.h> #include<stdlib.h> int main() { FILE *fp; char filename[80],ss[256]; printf("ファイル名="); gets(filename); if((fp=fopen(filename,"r"))==NULL){ printf("ファイルをオープンできません.\n"); exit(1); } while(fgets(ss,256,fp)!=NULL){ printf("%s",ss); } puts(""); fclose(fp); return 0; } ----------------------------------------- 初心者な内容の質問ですいません。 以上のプログラムでまず、「gets(filename);」により、「filename[80]」の配列に「aaa.txt」という文字列を格納し、そのファイルをfopenで読もう込もうとしています。 そこで、 if((fp=fopen(filename,"r"))==NULL) の部分に疑問があるのですが、「filename」という配列名だけで中身の「aaa.txt」と何故認識できるのでしょうか? 配列名ということで、先頭アドレスのみの情報しかないと思いました。 教えていただければ嬉しいです。

  • C言語のファイル読み込みに関して。

    英文を入力したテキストファイルを読み込むプログラムをつくっているのですが、 ファイル読み込みが上手くできません。 #include<stdio.h> main() { char filename[33]; char sty[512]; FILE *fp; printf("FILENAME: "); fgets(filename, 33, stdin); //読み込むテキストファイルを指定 fp = fopen(filename,"r"); if(fp == NULL){ printf("Can't open the file!\n"); return -1; } fgets(sty, 512, fp); fclose(fp); printf("%s\n",sty); } このプログラムなのですが、どうしても"Can't open the file!"が表示されてしまいます。 どうすればいいのでしょうか?

  • ファイルをドロップするとfopenからファイルが作成できません

    C言語でコンソールアプリケーションを作っています。 ファイルをexeにドロップして実行し、別のファイルに結果を出力させたいのですが、出力ファイルが作成されません。 どのようにすればよろしいのでしょうか。 コンソールから渡すときはファイルが作成されます。 コンパイラはBorland C++ Compiler 5.5を使用しています。 以下にコードの一部を掲載します。 int main(int argc, char *argv[]) {  char filename[256];  FILE *inputFile;  FILE *outputFile;  int i;  for(i=1; i<argc; i++)  {   if((inputFile=fopen(filename,"r")) == NULL)   {/*エラー処理*/}   sprintf(filename,"result%d.txt",i); // 出力ファイル名   if((outputFile=fopen(filename,"w")) == NULL)   {/*エラー処理*/}   for(;;)   {    char ss[1024];    if(fgets(ss,1024,inputFile) ==NULL) break;    fputs(ss,outputFile);   }   fclose(inputFile);   fclose(outputFile);  }  return 0; }

  • ファイル操作やポインタ、構造体について(C言語)

    C言語の課題で詰まってしまいました。宜しければ助言を宜しくお願いします。 コマンド選択で,0) 終了,1) 追加,2) 検索(id),3)変更 が行える学生成績管理プログラムを作成する。 データは,学生の番号 名前 GP 総単位数 形で学生のデータを持っているファイルである。 #include<stdio.h> #include<stdlib.h> #include<string.h> struct student{ int id; char name[25]; int gp; int credit; }; void add(char *, struct student);//追加 int search(char *, struct student *);//検索 void change(char *, struct student);//指定したidの学生の情報を変更 main(int argc,char *argv[]) { FILE *fp; int i = 0; int num; struct student students; if(argc == 1){ printf("set filename\n"); return 1; } while(1) { printf("1)add 2)search 0)quit "); scanf("%d",&num); if(num == 0) break; /* 追加 */ if(num == 1) { printf("id name gp credit ? "); scanf("%d %s %d %d", &students.id, students.name, &students.gp, &students.credit); add(argv[1], students); } /* 検索 */ if(num == 2) { printf("id ? "); scanf("%d", &students.id); if(search(argv[1],&students)){ printf("%d %s %d %d\n", students.id, students.name, students.gp, students.credit); } else{ printf("ID %d Not Found.\n",students.id); } } if(num == 3){ //変更 } } } /* 追加ルーチン */ void add(char *filename, struct student students) { FILE *fp; if((fp = fopen(filename, "a")) == NULL){ printf("can't open %s\n", filename); exit(1); } fprintf(fp,"%d %s %d %d\n", students.id, students.name, students.gp, students.credit); fclose(fp); } /* 検索ルーチン */ int search(char *filename, struct student *students) { FILE *fp; int id; char name[25]; int gp; int credit; if((fp = fopen(filename, "r")) == NULL){ printf("can't open %s\n", filename); exit(1); } while(fscanf(fp,"%d %s %d %d", &id, name, &gp, &credit) != EOF) { if(id == students->id){ students->id = id; strcpy(students->name ,name); students->gp = gp; students->credit = credit; return 1; } } return 0; fclose(fp); } /* 変更ルーチン */ void add(char *filename, struct student students){ } ------------ここまで------------ ファイルの操作での入出力は"a"や"r"、また"w"を利用するのかとも思いましたが、 指定したIDの内容を書き換えるにはポインタを2つ使う方法しか思いつかないのですが、与えられた問題で、変更のプロトタイプは void change(char *, struct student); となっていて、どうやるのかまったく見当もつきません。 稚拙な文で伝わりにくいかもしれませんが、 変更のやり方についてご教授願います。 見難くて申し訳ありません。 どうか宜しくお願いします。

  • ファイルの置換

    ファイルを置換するプログラムを作ったのですがうまく置換してくれません。コードは以下のように書きました。(コンパイラは出来ました) #include <stdio.h> #include <stdlib.h> #include <string.h> #define FALSE 0 #define TRUE 1 main() { FILE *fp; char filename[256]; FILE *outfp; char outfilename[256]; char key[128]; char str[128]; char c; int p; int keylen; int i=0 ; int search=FALSE; int count =0; printf(" enter filename"); scanf("%s",filename); printf("seach word"); scanf("%s",key); keylen=strlen(key); printf("change word"); scanf("%s",str); if((fp=fopen(filename,"r"))==NULL) { printf("file open error"); exit(1); } strcpy(outfilename,filename); strcat(outfilename,"_"); if((outfp=fopen(outfilename,"w"))==NULL) { printf("file open error"); exit(1); } while((c=fgetc(fp))!=EOF) { if(search) { if(c != key[i]) { search=FALSE; for(p=0;p<i;p++) { fputc(key[p],outfp); } fputc(c,outfp); i=0; } else{i++;} } else { if(c==key[i]) {search=TRUE;i++;} else {fputc(c,outfp);} } if (keylen==i) { count++; fputs(str,outfp); search=FALSE; i=0; } } fclose(fp); fclose(outfp); printf("apperance number %d\n",count); return 0; } どこか間違っていますか?教えてください。

  • newかFILEでエラーのような

    エラーがおこらないと思うんだけど、実行時エラーです。 コンソールアプリケーションのソースを見てください。 fclose(fp); を2行上に移動した場合はエラーにはなりません。 これはどうしてエラーになるんですか? test.txtは、同じディレクトリにある0バイトのファイルです。 #include <windows.h> #include <iostream.h> int main(){  WIN32_FIND_DATA finddata;  FILE *fp;  char *str;  char **pp;  FindClose(FindFirstFile("test.txt", &finddata));  fp = fopen("test.txt", "r");  if(fp){   str = new char[14];   fclose(fp);   strcpy(str, "abcdefghijklm");   pp = new char*[3];   pp = &str;   delete [] *pp;   delete [] str;  }else cout << endl;  return 0; }

  • ファイル書き込み操作について

    C言語でファイル書き込みを行う以下のプログラムを改造したいと思っています。 #include <stdio.h> #include <stdlib.h> int main() { char filename[10] = "output"; char strs[][10] = { "1.aaa\n" ,"2.\n" ,"3.\n" } FILE* fp; int i; int length; fp = fopen(filename , "w"); if (fp == NULL) { printf("cannot open file\n"); exit (1); } length = sizeof(strs)/10; for( i = 0; i < length ; i++ ) { fputs( strs[i], fp ); } fclose(fp); return 0; } この場合、outputの内容は、 1.aaa 2. 3. となりますが、 2行目にはscanf等を使いプロンプトから読み込んだbbbという文字列、 3行目にはtxtファイルから読み込んだcccという文字列を書き込むというような仕様にしたいと思っています。 その結果outputは、 1.aaa 2.bbb 3.ccc となるようにしたいです。 サンプルを改良してこのような仕様を満たすプログラムができますでしょうか?回答よろしくお願いします。

  • 外部パラメータを使用したファイルの作成・書き込み

    テキストファイルに以下の内容が書かれています。 ファイルパス:/aaa/bbb/ccc ファイル名:ファイル.txt これを読み込んで $filepath = /aaa/bbb/ccc $filename = ファイル.txt となっています。 この時(「ファイル.txt」は存在しません。)、以下のような処理を行うと「/aaa/bbb/ccc」ではなく、「/aaa/bbb」に「ファイル.txt」が作成されるのですが、なぜでしょうか?? open(TXT, ">> $filepath/$filename"); flock(TXT, 2); print TXT $header; flock(TXT, 8); close(TXT); この処理の前に$filepathの値を調べましたが、確かに「/aaa/bbb/ccc」となっています。 何か注意する点や、ここが問題では?と言うようなことがあれば教えてください。

    • ベストアンサー
    • Perl