• ベストアンサー

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

現在コマンドライン引数を利用した、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のテキストファイルが急に開けなくなってしまいました。 どうにも原因・解決策が分かりませんでしたので、お聞きしたくこちらに書き込みをさせてもらいました。 どなたか分かる方いらっしゃいましたらよろしくお願いします。

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

  • ベストアンサー
  • 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