• ベストアンサー

ファイルがオープンできない

現在コマンドライン引数を利用した、Drag&Dropで入力されたバイナリファイルをテキストファイルに出力するプログラムをCで作成しています。 その過程で、Drag&Dropされたファイル以外にもテキストファイル(option.txt)を読み込みたいのですが、どうしてもそのファイルをオープンすることができません。 次は問題の部分だけを抜き出したソースです。 #include <stdio.h> int main(int argc,char *argv[]) {  FILE *s;  s=fopen("option.txt","r");  if( !s ){   printf("Error: cannot open file(option.txt)\n");  }   else printf("OK!\n");  if(argc == 2) printf("%s\n",argv[1]);  else if(argc ==1) printf("No Drag&Drop File\n");  return 0; } Drag&Dropしない時(作成された実行ファイルをダブルクリックで起動する時)は  OK!  No Drag&Drop File となり、問題のoption.txtのファイルは開けているのですが、適当なバイナリファイル(7.chn)をDrag&Dropすると  Error: cannot open file(option.txt)  C:\Documents and Settings\[ユーザー名]\デスクトップ\Program\7.chn と、先ほどまで開けていたoption.txtのテキストファイルが急に開けなくなってしまいました。 どうにも原因・解決策が分かりませんでしたので、お聞きしたくこちらに書き込みをさせてもらいました。 どなたか分かる方いらっしゃいましたらよろしくお願いします。

  • Bohr
  • お礼率13% (2/15)

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

  • ベストアンサー
  • venzou
  • ベストアンサー率71% (311/435)
回答No.13

#11回答者です。 >よって、argv[0]でフルパスが取れるか否かは処理系次第です。 #7の回答・補足から処理系は判明しています。 WindowsXP Borland C++ Compiler 5.5 同じ環境で動作確認しましたので、問題ないと思いますが、違うバージョンのWindowsで動かす予定があれば念のため動作確認した方が良いかも知れませんね。 ついでに、とことん手抜きのプログラム書くと・・・ 実行ファイルのファイル名の長さは決まっていると思うので、こんな感じで。 #include <stdio.h> #include <string.h> #define EXEFILE_LEN 7 //実行ファイルのファイル名の長さ void main(int argc,char *argv[]) { char str[1024]; //エラー処理してないので多めに strcpy(str,argv[0]); str[strlen(argv[0])-EXEFILE_LEN] = '\0'; //ファイル名の前で切る strcat(str,"option.txt"); puts(str); {char c = getchar();} }

Bohr
質問者

補足

そうですね、大学のPCにWindows98がひとつありますのでそれでの動作確認だけはしたいと思います。 こういう'\0'を挿入する方法は思いつきませんでしたね。 確認しましたが、こちらでも正常にフルパスが取得できました。 ちなみに、私の考えたプログラムはこのような感じです #include<stdio.h> #include<string.h> int main(int argc,char *argv[]) { char m[200]=""; char*j=strrchr(argv[0],'\\'); //後ろから最初の\を検索 int k=j-argv[0]+1; strncpy(m,argv[0],k); strcat(m,"option.txt"); printf("Path : %s\n",m); fflush(stdin); getchar(); }

その他の回答 (14)

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.15

# 自分用(?)の簡単なツールのようなので蛇足かも知れませんが。 > char*j=strrchr(argv[0],'\\'); //後ろから最初の\を検索 この処理では、実行ファイル名に特定の漢字が入ると意図しない動作になりますね。 # わざわざ自作しなくても、パスだけ取るのは_splitpathで、合成は_makepathで可能だと思うのですが。 # (実際の関数名は、_splitpathのように先頭にアンダスコアがつきます)

Bohr
質問者

お礼

今まで教えていただいたことを参考に、一応プログラムが完成しました。 期待通りの出力が得られましたので、ひとまずこれでよしとしたいと思います。 これまで教えてくださった方々ありがとうございました。

Bohr
質問者

補足

そういう問題があるのですか、知りませんでした。 特にファイル名には漢字等は使用しないので大丈夫かとは思われますが、_splitpathを用いたoption.txtのフルパスを取得する関数も別に自作してありますので、何か不都合があればこちらに切り替えることにしますね。

回答No.14

凄いなぁ、ユーザが実行ファイルのファイル名を変えると動かなくなるプログラムですか。 あー、エクスプローラ上で、同じフォルダ内でコピペしただけでも動かなくなるんですね? いや、凄いなぁ。「専門家」にはできない芸当ですね。 あ、念のために補足しておきますと、argv[0]にフルパスが入るか否かはOS依存じゃなくて処理系依存ですから。 つまり、BCCではなく他のコンパイラにすると使えなくなる(かもしれない)手法ってことです。 この件に関しては私も専門家ではないのでVCではどうなるか知りませんが、 少なくともgccでは巧くいかないことは判っています。

Bohr
質問者

補足

>凄いなぁ、ユーザが実行ファイルのファイル名を変えると動かなくなる>プログラムですか。 >あー、エクスプローラ上で、同じフォルダ内でコピペしただけでも動か>なくなるんですね? >いや、凄いなぁ。「専門家」にはできない芸当ですね。 ??? >BCCではなく他のコンパイラにすると使えなくなる(かもしれない)手法っ>てことです。 なるほど、Windows98でもbccなら同様に動作するということですね。 それの確認も含めて、今度動作確認してみることにします。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.12

念のための補足です。 C/C++の言語仕様では、argv[0]は「呼ばれたプログラム名」か「空文字("")」のいずれかが入ることになっており、 (まぁ現実にはPCで空文字って事は通常ないですが) 空でない場合も、ここでいうプログラムが絶対パスなのか、ユーザの入力文字列そのままなのか、 ファイル名だけなのか、等については規定されていません。 よって、argv[0]でフルパスが取れるか否かは処理系次第です。 # 入力文字がそのまま取れる奴とかもあります。

Bohr
質問者

補足

argv[0]は処理系に左右されるのですね。 このプログラムは大学での実験データの解析に用いますので、大学のPCで使用できればそのまま使いたいと思います。 もし、不具合が起きるようならGetModuleFileNameの方を用いることにします。 補足ありがとうございました。

  • venzou
  • ベストアンサー率71% (311/435)
回答No.11

#include <stdio.h> void main(int argc,char *argv[]) { char c; puts(argv[0]); c = getchar(); } 実行ファイルのパスは argv[0] を見れば分かると思いますよ。

Bohr
質問者

補足

argv[0]でパスは確認できたのですね。 そちらを用いて、最後の実行ファイル名を削除し、"option.txt"を追加する方法でoption.txtのフルパスを取得することができました。 ちなみに、先ほど教えていただいたGetModuleFileNameとsplitpathを使う方法でもフルパスを指定するのに成功しました。 しかし、argv[0]の方がシンプルなコードで表現できましたので、前者の方を採用したいと思います。 これで、思い通りのプログラムを組むことができそうです。 ご教授いただきありがとうございました。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.10

ちなみに、makepathってのもあるので、実行ファイルのパスが取れれば、 そこからoption.txtの絶対パスを作るのもできるでしょう。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.9

失礼、ファイルオープンだけが目的なら最後のディレクトリ移動は不要ですね。 splitpathまでできれば十分。

Bohr
質問者

補足

なるほど、少し調べてみましたら、splitpathでディレクトリ、ドライブ、ファイル名、拡張子別に文字列を切り分けるのですね。 わかりました、参考にしながらプログラムを組んでみようと思います。 どうもありがとうございました!

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.8

"C:\Documents and Settings\[ユーザー名]" ここだとすると、「止まっている」というより「ユーザのルート」かも。 直接D&Dしてるので、パスがそこになってるとか。 ためしに、デスクトップなどのユーザ配下ではないディレクトリに全ファイルを置いてD&Dするとどうなりますか。 それでも上記ディレクトリになるなら、止まっているわけではないことになるかと思います。 # GetModuleFileNameだと実行ファイルの絶対パスが取れるので、 # option.txtという名前からすると、上記をsplitpath等して、 # SetCurrentDirectoryとかする方がいいのかもしれませんが。

Bohr
質問者

補足

ご指摘通り、"C:\"や"..\デスクトップ"など、いろいろなところで試してみましたが、すべてカレントは "C:\Documents and Settings\[ユーザー名]" となっていました。 ですので、MrBanさんのおっしゃるとおり「止まって」はいないようですね。 相対パスは無理そうなので諦めることにして、絶対パスの取得がGetModuleFileNameでできるということですので、勉強してこれから試してみることにします。

  • venzou
  • ベストアンサー率71% (311/435)
回答No.7

WindowsXP Borland C++ Compiler 5.5 上記の環境で確認しましたが、Drag&Dropで起動すると、 C:\Documents and Settings\[ユーザー名]\ プログラムのパスにも、Drag元のパスにも関係なく、常に上記がカレントディレクトリでした。 きっとcmd.exeのデフォルト設定でしょう。

Bohr
質問者

補足

私の環境も全く同じなので、何かこちらのバグというわけではないようですね。 仕方がありませんので、相対パスは諦めてフルパスでoption.txtを指定するようにします。 調べていただいて、どうもありがとうございました。

  • venzou
  • ベストアンサー率71% (311/435)
回答No.6

#include <stdio.h> #include <windows.h> void main(void) { char s[255]; char c; GetCurrentDirectory(255,s); printf("%s\n", s); c = getchar(); } こんな感じで、実行時のカレントディレクトリを確認すればすっきりするかも。

Bohr
質問者

補足

カレントディレクトリを調べるコマンドがあったのですね。 試してみましたところ、 "C:\Documents and Settings\[ユーザー名]" で止まっていました。 Drag元もDrop先もoption.txtも実行ファイルのある "C:\Documents and Settings\[ユーザー名]\デスクトップ\Program" に存在するので、このディレクトリがカレントになっているのが疑問です。

  • nerosuke
  • ベストアンサー率33% (39/115)
回答No.5

No1です。 他の人の回答で質問の意味が解りました。 ちなみにコンパイル、実行し、質問内容の確認をしました。 "option.txt"をフルパスにすれば解決します。 失礼しました!

Bohr
質問者

補足

すみません、表現がわかりづらかったようですね。 ご指摘とおりフルパスで試してみたところ、こちらでもファイルが開けることが確認できました。 本当は相対パスのほうが便利でよかったのですが、他の方がおっしゃっていたように、Drag元のディレクトリでカレントディレクトリが変わってしまうようであれば、絶対パスの方がいいのかもしれません。 ありがとうございました。

関連するQ&A

  • コマンドラインから引数を渡すことについて

    ----------------------------------------------- #include<stdio.h> #include<stdlib.h> int main(int argc,char *argv[ ]) { FILE *fin,*fout; char ss[256]; if(argc != 3){ printf("引数の数が違います\n"); exit(1); } if((fin=fopen(argv[1],"r"))==NULL){ printf("入力ファイルをオープンできません\n"); exit(1); } if((fout=fopen(argv[2],"w"))==NULL){ printf("出力ファイルをオープンできません\n"); exit(1); } while(fgets(ss,256,fin)!=NULL){ fputs(ss,fout); } fclose(fin); fclose(fout); return 0; } ----------------------------------------------- 以上のプログラム名は「tcopy.cpp」でコマンドプロンプトから実行し、ファイルをコピーするという事を行っていきます。 「aaa.txt」と「bbb.txt」の2つを用意し、「aaa.txt」の内容、 abcdef ABCDEF 012345 を「bbb.txt」にコピーしていきます。 そこで疑問なのですが、ファイルをコピーする際、コマンドプロンプトから、 >tcopy aaa.txt bbb.txt と打ち込むとコピー出来るようであり、「tcopy」、「aaa.txt」、「bbb.txt」が引数になるという事なのですが、何故この3つが引数になるのかという事と、 int main(int argc,char *argv[ ]) のargcに引数が何故代入されるかが分かりません。 後、「aaa.txt」と「bbb.txt」がargv[1]とargv[2]に何故対応しているかが分かりません。 教えていただければ嬉しいです。

  • CSVファイルの内容を構造体に格納したい(Unix使用)。

    こんにちは。私は30代の男性です。 「名前」「身長」「体重」が記載されたCSVファイルの内容を読み取って、構造体の「name」「height」「weight」に格納するプログラムを作っています。CSVの内容は A,175,80 B,167,89 C,155,45 ・ ・ ・ Z,188,70 だと仮定します。数値が読み取れているか、下記のように「tp = strtok(file_image, ",\n" );」の前後に「printf("%s\n", file_image);」を置いてみたら、strtok前では全て表示されるのに、strtok後では「ABC」しか表示されません。これでは全てのデータを構造体に格納できないので、困っています。 1.どのようにすれば、数字も取り出せる(読み取れる)でしょうか? 2.効率よく構造体に格納するには、どのようにしたらよいでしょうか? アドバイスを頂ければ幸いです。宜しくお願いいたします。 #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> int main(int argc, char *argv[]) { FILE *fp = NULL; int rtn = 0; if ((fp = fopen(argv[1], "r")) == NULL) { printf("ファイルオープンに失敗しました。\n"); return 1; } if (argc != 2) { printf("ERROR: オプションの数に過不足があります。\n"); return 1; } rtn = change_csv(fp); return 0; } int change_csv(FILE *fp) { int i; int j; char file_image[256]; /* 読み込んだ先のメモリの領域 */ char *tp; for (i = 0; i <= 256; i++) { if (fgets(file_image, 256, fp) == NULL) { if (ferror(fp) != 0) { printf("ERROR: 読み込みに失敗しました。\n"); return 1; } } if (feof(fp) != 0) { break; } printf("%s\n", file_image); tp = strtok(file_image, ",\n" ); printf("%s\n", file_image); } fclose(fp); return 0; }

  • バイナリデータをテキストファイルに出力したい

    以下のソースファイル(test.c) が、 バイナリデータをテキストファイルに するものらしいのですが、 ファイル名(例えば bi.dat)を指定する方法が わかりません。 C++は勉強し始めたばかりで 詳しくありません。 よろしくお願い致します #include <stdio.h> int main( int argc, char *argv[]) { FILE *fpIn; FILE *fpOut; short snData; if( argc < 2) { printf("ファイル名を入れてください。"); return -1; } fpIn = fopen( "argv[1]" , "rb"); if( fpIn == NULL) { printf("入力ファイル %s を開けませんでした。", argv[1]); return -2; } fpOut = fopen( "output.txt", "w"); if( fpOut == NULL) { printf("出力ファイル output.txt を開けませんでした。"); fclose(fpIn); return -3; } while( fread( &snData, sizeof(short), 1, fpIn) == 1) { fprintf( fpOut, "%d\n", snData); }; fclose(fpIn); fclose(fpOut); return 0; }

  • バイナリファイルをテキストファイルに変換する方法を教えて頂けませんか。

    こんにちは。 バイナリファイルをテキストファイルのように読み込んだり、書き込んだりすることは可能でしょうか。バイナリファイルをテキストファイルとして扱う良い方法があれば是非ご教授頂きたいです。 以下は自分なりに考えたプログラムなのですが、すごく文字化けして出力されてしまいます。どこがいけないんでしょうか。 ####プログラム#### #include<stdio.h> int main(){ FILE *fp,*fp2; char str[1024]; //file.txtはバイナリファイルなのでバイナリモードで開く if((fp = fopen("file.txt","rb")) == NULL){ printf("file.txt:open error"); exit(-1); } //out.txtはテキストファイルとして保存したいのでテキストモードで開く if((fp2 = fopen("out.txt","at")) == NULL){ printf("out.txt:open error"); exit(-1); } //一行ずつバイナリファイルをテキストファイルにして保存 while((fgets(str,1024,fp)) != NULL){ printf("%s\n",str); fprintf(fp2,"%s\n",str); } fclose(fp); fclose(fp2); return 0; } ####ここまで#### 以下が出力されたテキストファイル(out.txt)です。 ^A^Dc ^A^D^L<87> ^Y<98>X^?m?;^D&ordm;?^QI&egrave;&Ccedil; ^A^Dc ^A^D^L<87> ^Y<98>X^?m?;^D&ordm;?^QI0g 酷い文字化けを起こしてしまっています。 解決方法をご存知であれば教えて頂けないでしょうか。どうぞよろしくお願いします。

  • 任意のファイルを別のファイルにコピーするプログラム。

    コマンドラインからコピー元、コピー先ファイル名を指定してファイルをコピーするプログラムなんですが… #include <stdio.h> #include <stdlib.h> main(int argc, char *argv[]) { FILE *fp; if ((fp = fopen(argv[0],"r") == NULL){ printf("ファイル%sが存在しません。\n",argv[0]);exit(-1); } if ((fp = fopen(argv[1],"w") == NULL){ printf("ファイル%sがコピーできません。\n",argv[1]);exit(-1); } fclose(fp); } どこか間違っているところがあるでしょうか? ありましたら詳しく教えてもらえると幸いです。 少し自信がないのでわかる方はよろしくおねがいします。

  • ファイル操作のプログラム

    アルファベットの小文字を大文字に変換しながらファイルをコピーするプログラムですが形として書いてみたのですが・・・小→大に変換する場所、コマンドライン引数、細かい間違い等教えてくださればと思います。プログラムの条件として ・コマンドラインには,「実行プログラム名」「コピー元ファイル名」「コピー先ファイル名」を入力してプログラムを実行し,これらを引数としてコピーを行う. ・ コマンドラインへの入力が正しく行われているか(コピー元ファイルやコピー先ファイルも入力されているか)確認を行う. ・ファイルから読み取った文字が,小文字であるかを判断する必要があるので,ファイルから文字を「1文字ずつ」読み取って, 小文字であれば変換してコピー先に出力, その他の場合はそのままコピー先に 見にくいものではありますがよろしくお願いします。 #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[])) { FILE *infp, *outfp; int ch; if ( argc != 3 ){ /* コマンドラインからの入力が正しいか */ printf("There is no FILE NAME. \n"); exit(1); } if ( infp != argv[1] ) { printf("INPUT FILE OPEN error. \n"); } else { if ( outfp != [2] ) { printf("OUTPUT FILE OPEN error. \n"); } else { /* 入力・出力ファイルの条件が整ったので,コピー作業を行う */ if ((infp = fopen(argv[1], "r")) == NULL) { /* コピー元ファイルのオープン */ printf("can't open %s\n", argv[1]); return 1; } if ((outfp = fopen(argv[2], "w")) == NULL) { /* コピー先ファイルのオープン */ printf("can't open %s\n", argv[2]); fclose(infp); /* コピー元ファイルのクローズ*/ return 1; } while ((ch = fgetc(infp)) != EOF) { fputc(ch, outfp); /* コピー先ファイルにコピー元ファイルの内容を書き込む*/ } fclose(infp); } fclose(outfp); } return 0; }

  • ファイルの出力

    コマンドラインで指定したファイルの内容を一行ずつ表示するプログラムです。一行表示するごとに次の行も表示するか尋ねます。 #include<stdio.h> #include<stdlib.h> #include<ctype.h> int main(int argc, char *argv[]) {  FILE *fp;  char str[80];  char ch;  if (argc != 2){   printf("コマンドライン引数が違います\n");   exit(1);  }  if ((fp = fopen(argv[1],"r")) == NULL){   printf("ファイルが開けません");   exit(1);  }  while(!feof(fp)){   fgets(str, 79, fp);   if (!feof(fp)) printf("%s",str);   printf("追加しますか?(y/n)");   gets(str);   if ( toupper(*str) == 'N') break;   printf("\n");  }     if (fclose(fp) == EOF){   printf("ファイルを閉じれません\n");   exit(1);  }  return 0; } while文の   gets(str);  if ( toupper(*str) == 'N') break; この部分を  ch = getchar();  if ( toupper(ch) == 'N') break; でやると上手く実行できないのですが、なぜでずか?

  • テキストファイルが開けません。

    main関数に2つの引数をとり、第1引数で指定したファイルの内容を第2引数で指定したファイルにコピーするプログラムを以下のように作りました。 #include<stdio.h> #include<fcntl.h> int main(int argc, char* argv[]){ int fd1, fd2, rs, ws; char buffer[10000]; if(argc!=3){ write(2, "使用法:実行ファイル コピー元ファイル コピー先ファイル\n", 54); exit(1); } fd1=open(argv[1], O_RDONLY); if(fd1<0){ fprintf(stderr, "can't open file '%s'.\n", argv[1]); exit(1); } fd2=open(argv[2], O_WRONLY|O_CREAT|O_TRUNC); if(fd2<0){ fprintf(stderr, "can't open file '%s'.\n", argv[2]); exit(1); } while((rs=read(fd1, buffer, 10000))>0){ if((ws=write(fd2, buffer, rs))!=rs){ write(2, "an error occurred while copying.\n"); exit(1); } } close(fd1); close(fd2); } コンパイル、実行ともに正常終了したのですが、 コピー先のテキストファイルを開こうとすると、 「アクセスは拒否されました。」というダイアログが表示されて 開くことができません。 なぜなのでしょうか。 よろしくお願いします。 ちなみにOSはWindows Vistaで、 プログラムはcygwin上で実行しました。

  • UNIX上でのファイルopenについて

    C言語で同一ディレクトリから複数のファイルを順番に読み込んでいきたいのですが、うまくいきません。 シェルで、ファイル名の取得を行っていっています。 shell ---- ls /home/data > /home/src/infile.txt ---- C ----------------------------- FILE *fp; char y[30]="/home/data/"; // ↓aには上記シェルにて取得した1件目のファイル名が入っています。 strcat(y,a); // ↓ここでは絶対パスが正しく表示されます printf("ddd:%s\n",y); // ddd:/home/data/11.txt // ↓ここでfile open errorで一件目で終了してしまいます。 if ((fp = fopen(y,"r")) == NULL){ printf("file open error!!\n"); exit(1); } ----------------------------- このようなファイルの読込みのやり方ができるのか教えてください。 もしできるのであるのなら、そのやり方も教えてください。 わかりにくい文章ですが、お願いします。

  • C言語 コマンドラインの文字列を調べる方法

    はじめまして。 C言語を学習しています。 PCのOSはWindows XPです。 参考書に、アプリケーションの動作を指定するオプションを指定する方法として、下記の説明とプログラムが載っています。 以下の点でつまづいており、ご教示をお願い致します。 1、プログラム実行結果画面(コマンドプロンプトのような黒い画面。スクリーンショットを添付しております。)に【-a】と入力しようとしましたが、テンキーの【-】を押した時点で画面が消えてしまいます。 どのように操作すれば、参考書のような実行結果が得られるのでしょうか。 2、【argc--;】の部分で、ここでなぜデクリメントを使うのでしょうか。 3、argvは文字配列へのポインタ変数とのことですが、if文のところの【argv[argc][0]】が何を意味しているのか教えてください。 argv[配列の要素]のような書き方ではなく、argvの横に[]が2つある時点で混乱してしまいます。 どうかよろしくお願い致します。 ●参考書による説明 一般的に、コマンドラインにはファイル名の他に、アプリケーションの動作を指定するオプションを指定することがあります。 例えば、Windowsでファイル名を指定して実行で defrag と指定して起動すると、デフラグが起動して何もせずに終了しますが、 defrag c: と指定すると、Cドライブのデフラグを開始します。 また、defrag c: -a と指定すると、Cドライブの分析結果だけを表示します。 このような使い方は、パソコン上級者にはおなじみのやり方です。 この例では、 c: と -a という2つの文字列がコマンドラインに渡され、それをアプリケーション内で解析して、動作を決定しています。 同様のことは、コマンドラインの文字列を調べれば簡単にわかります。 ここでは、-a と -s というオプションの有無を解析する例です。 ●プログラム #include <stdio.h> int main(int argc,char *argv[]) { while (argc > 0) { argc--; if (argv[argc][0] == '-') { if (argv[argc][1] == 'a') printf("-a オプション\n"); if (argv[argc][1] == 's') printf("-s オプション\n"); } } return 0; } このプログラムに -a -s というオプションを与えて実行した結果は次の通りです。 -a オプション -s オプション 同様にすれば、いくつのオプションにでも対応することができます。 また、先頭が - ではない文字列をファイル名として扱うようにすれば、 ファイル名も前項と同様に取得することができます。

専門家に質問してみよう