みなさん、はじめまして。
【環境】WindowsXP , MFC(VC6.0)
現在、MFCでダイアログベースのアプリケーションを作成中です。
物理的にテキストファイルが開いているかどうかをチェックする方法がわからなくて困
っています。アプリ実行中にファイルを書き換えられては困るため、ファイルが開いて
いたらエラーメッセージで通知するようにしたいのですがなにか良い方法はありません
でしょうか?
いまファイルが見つからない場合のみエラー処理が完了しています。
FILE* fp;
fp = fopen(Sample.txt, r);
if(GetLastError() == ERROR_FILE_NOT_FOUND) {
AfxMessageBox(ファイルが見つかりません。);
return FALSE;
}
else if(ここがわからない!) {
AfxMessageBox(ファイルが開いています。\n閉じてから再度実行してくださ
い。);
return FALSE;
}
以上、よろしくお願いします。
FILE* fp;
fp = NULL;
if(fp != NULL)
じゃだめ?
fopenにはそのような機能はありません。
CStdioFileを使ってファイルを開くと、
既に他のアプリで開いている場合には、開けなくしたり、
逆に、開いてる間に、他のアプリが開けないように指定できますよ。
_fsopen()で、_SH_DENYRWでオープンしてみるのはどうでしょうか?
で、オープンに失敗した場合に、_findfirst()とかで、FindFirstFile()などで、
そのファイルの存在を確認して、ファイルが存在しない場合と区別するとかは?
みなさんレスありがとうございます。
>ぴかさん
読取専用で開くと開けてしまうのでfopen()はNULLを返してくれません。
>KING・王さん
_fsopen()試してみました。が、やはり読取専用で開くと開けてしまいます。。。
>REEさん
>既に他のアプリで開いている場合には、開けなくしたり、
他のアプリというか、エクスプローラからダブルクリックして開いた状態なのですが、
できますでしょうか?モードの指定が悪いのかうまくできませんでした。もう少し試し
てみます。。
CStdioFileを使って引数にCFile::shareExclusiveを指定してみましたが解決には至りま
せんでした。プログラム側で先にオープンしたファイルを物理的に開こうとすると別の
プロセスが使用中ですとメッセージがでたのですが、これを逆にしたいです。つまり先
に物理的に開かれているファイルを、プログラムが開くとエラーメッセージがでて開け
ない、というような。うーん。。。
僕の場合はCFileを使ってやったのでちょっと違うかもしれませんが。。。
CFile OpenData;
BOOL FileCheck=TRUE;
FileCheck=OpenData.Open(ファイルパス,CFile::modeRead);
if(FileCheck==TRUE)
{
開くときの処理
}
else
{
他のアプリなどで使用中の場合FileCheckはFALSEになります。
AfxMessageBox(他のアプリで使用中です。);
}
これで一応は動くと思います、至らない点などありそうなのでできる方から
ご指摘受けるかもしれませんが。。。
排他指定なし/共有可能な状態で開かれているファイルは、判断できないような。
排他なしで開いている奴がいるなら、「開かれていることを気にしなくていい状態」な
はずですよね、理屈的には。
> BOOL FileCheck=TRUE;
MSDN(仕様書)をよく読んだ方がいいです。CFile::Openは以下の仕様です。
<MSDN>
ファイルが正常に開いた場合は 0 以外を返します。それ以外の場合は 0 を返します。
</MSDN>
WindowsにおけるTRUEは1ですよ。(BOOLとbool,TRUEとtrueとは別物です)
どこにも1が返るなんて書いてないですよね。
こういうチェックは FALSE(0)とするのがC/C++のお約束です。
更に、上記だけでエラーの原因を見ていないと、
そんなファイルがないのか、既に排他で開かれているのか、権限がないのか、
その他の原因か、などが特定できません。
「文章が開かれている」と「ファイルが開かれている」は別に考えないといけません。
例えばNotepadやWordpadなどでは、
「文書を開いている」状態であっても「FILE*は閉じられています」
fopen()されているのは読み取る瞬間や保存する瞬間だけです。
ウィンドウ上にファイル内容が表示されている状態かどうかをfopen()/CFile等で
検出するのは不可能です。
Wordみたいにファイルを開きっぱなしにする奴は検出できますけど...
Emacsも同様読み込み中だけファイルを開く仕様になっていますが、
上書き保存の防止のための小細工を行っています。
開いたときのファイル名+inode+タイムスタンプを覚えておき、
保存しようとする際にもう一度取得し、変わっていれば別プログラムが上書きしたと判断
ファイルを書き換えられては困るからエラーを出したいわけですよね。
基本的にはファイルのOpenを書込み排他で行っておいてひらっきぱなしにしておけば、
それで書き込みはできなくなると思いますけれど。
tetrapodさんが書かれているような場合でも多分書き込み時にエラーになるのでは?
書き換えられたら困るのであって読み込まれる分にはいいわけですよね。
しかも読み込んでいるほうは勝手にやっているわけだからそっちの結果がどうなっても
感知しなくてよいのでしょうし。
いずれにせよ、開いている側で排他をかけていれば検知できると思いますが、
排他無しで開いているのであれば、多分検知不能なので必ず事前にメッセージを
出すと言うのは多分無理だと思います。
目的が達成できる他のアプローチを考えた方が良い様な気がします。
>「文書を開いている」状態であっても「FILE*は閉じられています」
なるほど、そうでしたか・・・。
>開いている側で排他をかけていれば検知できると思いますが、
排他無しで開いているのであれば、多分検知不能なので必ず事前にメッセージを
出すと言うのは多分無理だと思います。
ただ文書を開いているのでは排他がかからないみたいですね。
PATIOさんが言われるようにFILE*を開きっぱなしにすることにします。
みなさんどうもありがとうございました。
[解決済]ですが、ちょっと発言
『ファイルOpenするアプリケーションが自作同士で、ファイルOpen中なら
ファイルOpenできないように排他を取る』限定ならですが、
CreateFile()の何等かの引数設定で出来るのでは?
(MFCではないですが)
用途が理解しきれていないので、的外れかもしれませんね・・・?
その条件ならCreateFile(やそのMFCラッパーCFileなど)でも可能ですが、
I/Fがちょっと違うだけで、内部的な動作はFILE*でも本質的に一緒です。