こんにちわ、よっさんと申します。
前にも同じような質問をさせていただいたのですが、
原因が追求できずに困っています。
開発環境:WIN2000 VC++6.0 WIN32コンソールアプリ
_findfirst()に、正しいパスを引数で渡しているのですが
ファイル名不正のエラーが出てしまいます。
指定したディレクトリに、指定した名前のファイルが
あるのにもかかわらず「EINVAL」のエラーが出てしまう、
このような場合にどのような事がエラーの原因に成り得る
のでしょうか。
[処理の流れを以下に記します]
□指定したディレクトリのファイルは不定期にファイルが
作成されます。
□その作成されたファイルを、_findfirst()で
ファイルが作成されたかどうかを監視しています。
□ファイルが、_findfirstで取得できた場合には、
そのファイルを削除します。
もしかしたら、ファイルが出来た瞬間?に_findfirstで
取得しに行ったときに、エラーしているではないのかと、
思っているのですが、そのようなことがあるのでしょうか。
どなたか分かる方がいらっしゃいましたら、
ご教授宜しくお願い致します。
_findcloseのタイミングが悪いのでは?
?さん返信有難うございます。
_findcloseの場所は、_findcloseのエラー処理
ではしていないですし、特に問題は無さそうです。
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200207/02070124.txt
だとすると
>ループで、findfirst関数を使用しているのですが、
>一回目は正常にファイル情報を取得して、正常値を
>返してきます。
>2回目のfindfirstで、エラー値を返してerrnoには
>EINVALを返してきます。
>_findcloseしている所は、_findfirst関数でエラー値が戻ってきた
>場合と、_findnext関数でエラー値が戻ってきた時です。
1回目のfindfirstの後、2回目のfindfirstの前にもfindcloseがいると思います。
>指定したディレクトリに、指定した名前のファイルが
確認タイミングと確認方法を教えてください
方法とタイミングによっては本当に存在しないものが
あるように見えることがあります
できれば現物(ソース)を乗せてください
多少の省略は可能です
?さん、woodさん返信有難うございます。
以下は、findfirst関数を使用したソースです。
この関数の呼び出し元は、常にループしています。
検索対象ファイルが見つかった場合に、その
ファイルを削除します。
検索対象ファイルは、不定期に作成しています。
#include dykxx000.h
int serchfile (char *pchBuf_File, char *pchBkCsv_Buf, time_t *Create_Time)
{
int inResult; /*
タイムスタンプの比較 */
int inRet_Findnext; /*
findnextの戻り値 */
int inGet_Flg; /*
新しいファイルの存在有無 */
int inMem_Ret;
/* memcmpの戻り値 */
struct _finddata_t c_File; /* _finddata_t 構造
体の宣言 */
long hlFile; /*
ハンドルの戻り値 */
time_t Save_Time; /*
一時保持時間 */
inGet_Flg = 0; /*
フラグの初期化 */
inResult = 0; /*
関数の戻りの初期化 */
Save_Time = 0; /*
一時保持時間の初期化 */
inRet_Findnext = 0; /*
findnextの戻り値を初期化 */
hlFile = 0;
/* ハンドルの初期化 */
inMem_Ret = 0; /*
memcmpの戻り値を初期化 */
errno = 0;
/* エラーnoの初期化 */
/* ファイル1件目の情報を取得する
*/
hlFile = _findfirst(pchBuf_File, &c_File);
if (hlFile != DYKXX_RET_ERR) /* ファイルが存在する場合
*/
{
/* 取得したファイル名がディレクトリ名でない場合
*/
if (c_File.attrib != DYKXX_DIR_PARM)
{
/* 初期時間より取得時間が新しい場合
*/
if (*Create_Time < c_File.time_write)
{
/* 一時保持時間に取得時間を格納する
*/
Save_Time = c_File.time_write;
/* 領域の初期化
*/
memset (pchBkCsv_Buf, (char)NULL, sizeof
(pchBkCsv_Buf));
/* バックアップCSV保管
*/
strcpy (pchBkCsv_Buf, c_File.name);
/* フラグを立てる
*/
inGet_Flg = DYKXX_FLG_ON;
}
}
}
else if(hlFile == DYKXX_RET_ERR)/* ファイルが存在しない場合
*/
{
if (errno == ENOENT) /* ファイルが存在し
ない場合 */
{
/* 呼び出し元に1(正常)を返す
*/
return (DYKXX001_NO_EXIST);
}
else if (errno == EINVAL) /* ファイル名が無効である場合
*/
{
return (DYKXX001_ERROR);/* 呼び出し元に-1(異常)を返す
*/
}
}
/* 次のファイルを取得する
*/
inRet_Findnext = _findnext(hlFile, &c_File);
/* 次ファイルが存在する場合
*/
while (inRet_Findnext != DYKXX_RET_ERR)
{
/* 取得したファイル名がディレクトリ名でない場合
*/
if (c_File.attrib != DYKXX_DIR_PARM)
{
/* 初期時間より取得時間が新しい場合
*/
if (*Create_Time < c_File.time_write)
{
/* フラグがONでない場合
*/
if (inGet_Flg != DYKXX_FLG_ON)
{
/* 時間を保管
*/
Save_Time = c_File.time_write;
/* 領域の初期化
*/
memset (pchBkCsv_Buf, (char)NULL,
sizeof(pchBkCsv_Buf));
/* バックアップCSV保管
*/
strcpy (pchBkCsv_Buf,
c_File.name);
inGet_Flg = DYKXX_FLG_ON; /*
フラグを立てる */
}
/* 一時保持時間より取得時間が古い場合
*/
if (Save_Time > c_File.time_write)
{
/* 一時保持時間に取得時間を格納する
*/
Save_Time = c_File.time_write;
/* 領域の初期化
*/
memset (pchBkCsv_Buf, (char)NULL,
sizeof(pchBkCsv_Buf));
/* バックアップCSV保管
*/
strcpy (pchBkCsv_Buf,
c_File.name);
}
}
}
/* 次のファイルを取得する
*/
inRet_Findnext = _findnext( hlFile, &c_File);
inMem_Ret = 0;
}
_findclose( hlFile); /* ファイ
ルクローズ */
*Create_Time = Save_Time; /* 取得時間を初期設
定時間に格納 */
if (inGet_Flg == DYKXX_FLG_OFF) /* フラグがOFFの場合
*/
{
return (DYKXX001_NO_EXIST); /* 呼び出し元に1(正
常)を返す */
}
return (DYKXX001_EXIST); /* 呼び出し元に0(正
常)を返す */
}
それでは、宜しくお願い致します。
コメントが、怪しいぐらいに
見づらくなってしまいました。
申し訳ありません。
根本的な問題解決とは別ですけど、こんなAPIもありますってことで
ご参考までに
FindFirstChangeNotification
FindNextChangeNotification
FindCloseChangeNotification
WaitForSingleObject
ファイル名が固定なら
HANDLE h = CreateFile(~, OPEN_EXISTING, ~)
if (h != INVALID_HANDLE_VALUE) {
BY_HANDLE_FILE_INFORMATION Info;
GetFileInformationByHandle(h, &Info);
CloseHandle(h);
}
なんて方法もあります(未確認です)
kuさん返信有難うございます。
検索ファイルパスは、ワイルドカード指定も
できることが前提になっています。
参考までに紹介していただいたAPIも、
調べてみようと思います。
エラーコードが32で落ちているみたいです。
32の場合は、ファイル共有アクセス違反ですよね。
_FindFirstがFileを掴んだまま離していないのか
と思うのですが、分かる方いらっしゃいましたら
ご教授お願い致します。
_findfirst、_findnextと、
FindFirstFile、FindNextFileの
2パターンでやってみましたが、
やはり1ファイル取得して、
そのファイルを削除して、
ファイル取得を再度行うと落ちて
しまいます。
対象ディレクトリに、何もファイルが
ない場合は正常に無限ループしています。
FindFirstFileで、検索すること自体が
いけないのでしょうか?
あまり信用できないAPIなのでしょうか?
もし、知っている方がいれば教えて
頂きたいのですが、宜しくお願いします。
しつこいようだけどCloseするタイミング
自分はCFileFindしか使わないので はずれかもしれないけど
DYKXX_RET_ERRというのは見たことがないけど
hlFile != INVALID_HANDLE_VALUE なら
Closeしてもいいのでは?
MSDNのFindFirstFileの頁のサンプルもそうだし
ソースを探すとCFileFind::~CFileFind() でもそうしてるし。
それでだめならCFileFindを使うか
ファイルの削除のほうに問題がないかしらべてみるとか・・・。
MSDNに
>_findfirst が返したハンドルは、_findfirst へ渡されるパスに含まれるディリクトリ
>の上で(削除などの)変更作業を行う前に、_findclose に渡されなければなりません。
こんな記述ありますけど関係ありませんかね~?
VC++5.0のヘルプ索引「_find、_wfind 系関数」ですけど・・・
?さん返信有難うございます。
_findclose()のタイミングは以下のような
ところで良いと思うのですが。
どうでしょうか?
--------------------------------------------
struct _finddata_t finddata;
long lHANDLE = 0L;
int iRet = 0;
int iReturn = 0;
lHANDLE = _findfirst(*.*, &finddata);
iRet = _findnext(lHANDLE, &finddata);
while( iRet != INVALID_HANDLE_VALUE ){
remove(取得ファイルパス);
iRet = _findnext(lHANDLE, &finddata);
}
_findclose(finddata);
return iReturn;
--------------------------------------------
↑すごく内容を省いたコードですが・・・。
> hlFile != INVALID_HANDLE_VALUE なら
> Closeしてもいいのでは?
hlFile == INVALID_HANDLE_VALUE っていう
事ですよね。
確かにどこのサンプルを見ても、errnoまで
判定しているのは見かけないですね。
ファイルを削除させた後に、もう一度上の関数を
CALLするとファイルの共有違反で落ちてしまう
のですが、ファイル削除をしてすぐにその
ディレクトリを検索しにいくと、共有違反になる
というのはあるのでしょうか?
特にスレッドを使用した処理はしてはいないので、
処理は順番に流れると思うのですが、どなたか
分かる方返信宜しくお願い致します。
woodさん、返信有難うございます。
すみません、上のソースコードremove()のタイミングがぜんぜん違いました。
remove()するタイミングは、この関数で1つのファイルを取得して、
呼び出し元で消します。
※上のソースは、_findclose()の位置の確認の為、という形でお願いします。
>_findfirst が返したハンドルは、_findfirst へ渡されるパスに含まれるディリクトリ
>の上で(削除などの)変更作業を行う前に、_findclose に渡されなければなりません。
この事なんですけど、_findfirst()で対象にしているディレクトリ内の
ファイルの変更作業は、_findclose()した後で行えば良いという事ですよね?
削除のタイミングは、_findclose()の後に行っている為、問題無いと思います。