こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

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

現在コマンドライン引数を利用した、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のテキストファイルが急に開けなくなってしまいました。

どうにも原因・解決策が分かりませんでしたので、お聞きしたくこちらに書き込みをさせてもらいました。

どなたか分かる方いらっしゃいましたらよろしくお願いします。

投稿日時 - 2006-12-16 15:54:18

QNo.2605622

困ってます

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

#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();}
}

投稿日時 - 2006-12-16 20:56:51

補足

そうですね、大学の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();
}

投稿日時 - 2006-12-16 21:29:40

ANo.13

このQ&Aは役に立ちましたか?

2人が「このQ&Aが役に立った」と投票しています

回答(15)

ANo.15

# 自分用(?)の簡単なツールのようなので蛇足かも知れませんが。

> char*j=strrchr(argv[0],'\\'); //後ろから最初の\を検索

この処理では、実行ファイル名に特定の漢字が入ると意図しない動作になりますね。

# わざわざ自作しなくても、パスだけ取るのは_splitpathで、合成は_makepathで可能だと思うのですが。
# (実際の関数名は、_splitpathのように先頭にアンダスコアがつきます)

投稿日時 - 2006-12-16 22:13:40

補足

そういう問題があるのですか、知りませんでした。

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

投稿日時 - 2006-12-16 23:13:43

お礼

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

これまで教えてくださった方々ありがとうございました。

投稿日時 - 2006-12-16 23:48:37

ANo.14

凄いなぁ、ユーザが実行ファイルのファイル名を変えると動かなくなるプログラムですか。
あー、エクスプローラ上で、同じフォルダ内でコピペしただけでも動かなくなるんですね?
いや、凄いなぁ。「専門家」にはできない芸当ですね。

あ、念のために補足しておきますと、argv[0]にフルパスが入るか否かはOS依存じゃなくて処理系依存ですから。
つまり、BCCではなく他のコンパイラにすると使えなくなる(かもしれない)手法ってことです。
この件に関しては私も専門家ではないのでVCではどうなるか知りませんが、
少なくともgccでは巧くいかないことは判っています。

投稿日時 - 2006-12-16 21:30:04

補足

>凄いなぁ、ユーザが実行ファイルのファイル名を変えると動かなくなる>プログラムですか。
>あー、エクスプローラ上で、同じフォルダ内でコピペしただけでも動か>なくなるんですね?
>いや、凄いなぁ。「専門家」にはできない芸当ですね。
???

>BCCではなく他のコンパイラにすると使えなくなる(かもしれない)手法っ>てことです。
なるほど、Windows98でもbccなら同様に動作するということですね。
それの確認も含めて、今度動作確認してみることにします。

投稿日時 - 2006-12-16 23:26:59

ANo.12

念のための補足です。

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

よって、argv[0]でフルパスが取れるか否かは処理系次第です。
# 入力文字がそのまま取れる奴とかもあります。

投稿日時 - 2006-12-16 20:32:19

補足

argv[0]は処理系に左右されるのですね。

このプログラムは大学での実験データの解析に用いますので、大学のPCで使用できればそのまま使いたいと思います。
もし、不具合が起きるようならGetModuleFileNameの方を用いることにします。

補足ありがとうございました。

投稿日時 - 2006-12-16 20:46:27

ANo.11

#include <stdio.h>
void main(int argc,char *argv[])
{
char c;
puts(argv[0]);
c = getchar();
}

実行ファイルのパスは argv[0] を見れば分かると思いますよ。

投稿日時 - 2006-12-16 20:09:02

補足

argv[0]でパスは確認できたのですね。

そちらを用いて、最後の実行ファイル名を削除し、"option.txt"を追加する方法でoption.txtのフルパスを取得することができました。

ちなみに、先ほど教えていただいたGetModuleFileNameとsplitpathを使う方法でもフルパスを指定するのに成功しました。

しかし、argv[0]の方がシンプルなコードで表現できましたので、前者の方を採用したいと思います。

これで、思い通りのプログラムを組むことができそうです。

ご教授いただきありがとうございました。

投稿日時 - 2006-12-16 20:28:58

ANo.10

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

投稿日時 - 2006-12-16 18:57:18

ANo.9

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

投稿日時 - 2006-12-16 18:12:15

補足

なるほど、少し調べてみましたら、splitpathでディレクトリ、ドライブ、ファイル名、拡張子別に文字列を切り分けるのですね。

わかりました、参考にしながらプログラムを組んでみようと思います。

どうもありがとうございました!

投稿日時 - 2006-12-16 18:19:46

ANo.8

"C:\Documents and Settings\[ユーザー名]"

ここだとすると、「止まっている」というより「ユーザのルート」かも。
直接D&Dしてるので、パスがそこになってるとか。

ためしに、デスクトップなどのユーザ配下ではないディレクトリに全ファイルを置いてD&Dするとどうなりますか。
それでも上記ディレクトリになるなら、止まっているわけではないことになるかと思います。

# GetModuleFileNameだと実行ファイルの絶対パスが取れるので、
# option.txtという名前からすると、上記をsplitpath等して、
# SetCurrentDirectoryとかする方がいいのかもしれませんが。

投稿日時 - 2006-12-16 18:04:39

補足

ご指摘通り、"C:\"や"..\デスクトップ"など、いろいろなところで試してみましたが、すべてカレントは
"C:\Documents and Settings\[ユーザー名]"
となっていました。

ですので、MrBanさんのおっしゃるとおり「止まって」はいないようですね。

相対パスは無理そうなので諦めることにして、絶対パスの取得がGetModuleFileNameでできるということですので、勉強してこれから試してみることにします。

投稿日時 - 2006-12-16 18:07:43

ANo.7

WindowsXP
Borland C++ Compiler 5.5

上記の環境で確認しましたが、Drag&Dropで起動すると、

C:\Documents and Settings\[ユーザー名]\

プログラムのパスにも、Drag元のパスにも関係なく、常に上記がカレントディレクトリでした。

きっとcmd.exeのデフォルト設定でしょう。

投稿日時 - 2006-12-16 17:56:15

補足

私の環境も全く同じなので、何かこちらのバグというわけではないようですね。

仕方がありませんので、相対パスは諦めてフルパスでoption.txtを指定するようにします。

調べていただいて、どうもありがとうございました。

投稿日時 - 2006-12-16 17:58:43

ANo.6

#include <stdio.h>
#include <windows.h>
void main(void)
{
char s[255];
char c;
GetCurrentDirectory(255,s);
printf("%s\n", s);
c = getchar();
}

こんな感じで、実行時のカレントディレクトリを確認すればすっきりするかも。

投稿日時 - 2006-12-16 17:44:00

補足

カレントディレクトリを調べるコマンドがあったのですね。

試してみましたところ、
"C:\Documents and Settings\[ユーザー名]"
で止まっていました。

Drag元もDrop先もoption.txtも実行ファイルのある
"C:\Documents and Settings\[ユーザー名]\デスクトップ\Program"
に存在するので、このディレクトリがカレントになっているのが疑問です。

投稿日時 - 2006-12-16 17:47:03

ANo.5

No1です。

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

失礼しました!

投稿日時 - 2006-12-16 17:03:03

補足

すみません、表現がわかりづらかったようですね。

ご指摘とおりフルパスで試してみたところ、こちらでもファイルが開けることが確認できました。

本当は相対パスのほうが便利でよかったのですが、他の方がおっしゃっていたように、Drag元のディレクトリでカレントディレクトリが変わってしまうようであれば、絶対パスの方がいいのかもしれません。

ありがとうございました。

投稿日時 - 2006-12-16 17:37:20

ANo.4

試してないので自信ないのですが"option.txt"を絶対パス("c:\\option.txt"など)で書いてみるのはどうでしょうか。(Drag&Dropで実行した場合、プログラムはDrag元で実行されたような気がします。)

投稿日時 - 2006-12-16 16:44:49

補足

絶対パスにするとちゃんと開くことができました。

しかし、Drag元とDrag先は実行ファイルやCのソースファイルがあるディレクトリにあり、そのディレクトリにoption.txtもありますので、カレントディレクトリにoption.txtもあるはずと思うのですが、この相対パスの指定方法で何が問題なのかが疑問には残るところではあります。

投稿日時 - 2006-12-16 17:16:59

お礼

すみません、お礼を書くのを忘れてしまいました!

Dragもとのディレクトリでプログラムが実行されるとしたら、別のディレクトリからDragした場合を考えると、絶対パスのほうがいいのかもしれないですね。

どうも、ありがとうございました。

投稿日時 - 2006-12-16 17:45:04

ANo.3

多分、「カレントディレクトリ」が違うせいかと思われます。

Drag&Drop時はカレントが、
C:\Documents and Settings\[ユーザー名]\デスクトップ\Program\
になっているので、単に"option.txt"とかくと、
C:\Documents and Settings\[ユーザー名]\デスクトップ\Program\option.txt
を開こうとします。で、これが見つからずにエラーになってます。

絶対パスにするなり、GetModuleFileName等の利用を検討してください。

投稿日時 - 2006-12-16 16:42:52

補足

いえ、そのoption.txtがあるディレクトリがカレントディレクトリですので、見つかるはずではないかと思うのですが、なぜかエラーが出てしまうという状況です。

絶対パスにしますとちゃんと開けましたので、相対パスが無理なようでしたら絶対パスでいきたいと思います。
それと初めてみましたがGetModuleFileNameというものもあるのですね。
こちらも調べてみようと思います。

ありがとうございました。

投稿日時 - 2006-12-16 17:10:57

ANo.2

実行時のカレントディレクトリが違うだけでは?

>s=fopen("option.txt","r");

ファイル名をフルパスで指定してみてください。

投稿日時 - 2006-12-16 16:39:43

補足

フルパスで指定するとちゃんと開けるようになりました。
ありがとうございます。

投稿日時 - 2006-12-16 17:07:21

ANo.1

今一質問の意味が解りません。

argcは引数に渡った文字列の個数ですので、Drag&Dropは関係ないですよ。 仮にコマンドで "実行ファイル名" "ファイル名"でもDrag&Dropした処理になりますよ。

まあそれはいいのですけど、気になるのはfcloseをしてないことですね。 fopenで開いた"option.txt"を閉じてません。

しかしながら、それで質問者が陥ってる状態にはならないと思いますが
・・・

開けなくなった状態でもoption.txtは存在しているんですか?

投稿日時 - 2006-12-16 16:35:49

補足

指摘いただいたように、忘れていたファイルのクローズを試してみましたが、やはり状況は変わりませんでした。

option.txtはソースファイル・実行ファイルの存在するディレクトリにちゃんとあります。
パスの指定の方法は間違ってはいないと思うのですが…。

投稿日時 - 2006-12-16 16:44:45

あなたにオススメの質問