CreateFile関数を用いたファイル作成について

このQ&Aのポイント
  • CreateFile関数を使用してファイルを作成する際に、リネーム処理後の作成日時が以前の作成日時になる問題が発生しています。
  • この問題の原因は、CreateFile関数がキャッシュファイルの情報を取得しているためです。
  • 解決方法としては、キャッシュファイルの情報をクリア(削除)することで、正しい作成日時でファイルを作成することができます。
回答を見る
  • ベストアンサー

CreateFile関数を用いたファイル作成について

VisualC++のCreateFile関数を用いて「作成日時が1週間前であれば ファイルをリネームして保存後、以前のファイル名で 空ファイルを作成する」という処理を作っています。 (作成中の関数の抜粋) /* リネーム処理 */ ret_code = MoveFile(logfile_path, rename_path); if(ret_code == API_NG){ return(NG); } /* 以前と同じ名前でファイルを新規作成 */ hfile = CreateFile(logfile_path, GENERIC_WRITE,FILE_SHARE_WRITE, NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_NO_BUFFERING); if( hfile == INVALID_HANDLE_VALUE ) { return(NG); } CloseHandle(hfile); } return(OK); } リネームする以前と同じ名前でファイルを作成すると ファイルの作成日時がリネームする以前の作成日時になってしまいます。 (例) 4月1日に「aaa.txt」を作成→ 4月8日に「aaa_0401.txt」にリネーム後、新規に「aaa.txt」を作成すると 作成日時が「4月1日」になってしまう。 Microsoftのページによると、キャッシュファイルの情報を取得しているために 以前の作成日時にてファイルが作成されてしまうようです。 http://www.microsoft.com/JAPAN/developer/library/jpwinpf/_win32_createfile.htm 原因は分かったのですが、対処方法が思い浮かびません。 上記問題を解決するにはどういった方法がありますでしょうか? ご教授をよろしくお願いします。

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

  • ベストアンサー
回答No.3

新しく作成したファイルに、SetFileTime APIで現在の日時を設定してはどうですか? GetSystemTime APIでシステム時間を取得して、SystemTimeToFileTime APIでファイル時刻へ変換しSetFileTime APIでファイルの時刻を変更すれば更新できそうですが、試していないので結果はわかりません。 http://msdn.microsoft.com/library/ja/jpsysinf/html/_win32_getsystemtime.asp http://msdn.microsoft.com/library/ja/jpsysinf/html/_win32_systemtimetofiletime.asp http://msdn.microsoft.com/library/ja/jpsysinf/html/_win32_setfiletime.asp

ofjk_77
質問者

お礼

ご指摘の通り、下記APIにて作成日時を更新することができました。 SystemTimeToFileTime→ LocalFileTimeToFileTime→ SetFileTime 言われてみれば「なるほど~」という対処方法で なかなか気づきませんでした(汗) どうもありがとうございましたm(_ _)m

その他の回答 (2)

  • yosi_yosi
  • ベストアンサー率35% (165/468)
回答No.2

いったん該当ファイルを削除して、それからもう一度作成したらよいと思いますよ。 DeleteFile()とか...

ofjk_77
質問者

お礼

MoveFile関数を、CopyFile&DeleteFile関数に変更しましたが、結果は同じでした。 (対処方法を勘違いしていましたらすみません) やはりキャッシュが悪さをしてるのでしょうかねぇ。

  • valvelde
  • ベストアンサー率35% (46/129)
回答No.1

新規にaaa.txtを作成せずに別の名前でファイルを作成した後、aaa.txtにリネームする。

ofjk_77
質問者

お礼

(引数は省略) (1)CopyFile(aaa.txt, aaa_0408.txt) ↓ (2)CreateFile(tmp.txt) ↓ (3)MoveFile(tmp.txt, aaa.txt) とすると、(3)にて作成日時が元に戻ってしまいました・・・ どうやらこちらの方法ではうまくいかないようです。

関連するQ&A

  • CreateFileしてからtruncate

    ファイルデータを置換するプログラムを作っています。 短い文字に置換すると、ファイルサイズは小さくなります。 ところが、今のソースではファイルサイズ小さくなりません。 「abcdefg」のテスト中の「cde」を「H」に置換すると 「abHfgxx」になってしまいます。 ・hfile = CreateFile("test.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ・読む ・置換 ・上書き ・CloseHandle(hfile); というステップです。 ・読む の直後に、text.txtを0バイトにしたいんですが、 hfileを閉じないで、Perlのtruncateのようなことはできませんか?

  • ファイルの作成日時について

    職場で簡単なファイルのバックアップPGをWSHで作っていますが ファイルの作成日時が思うように入ってくれません。 WSHの流れは下記にしたいと考えています。 (1)前回分のファイルを作成日時を末尾に付けてリネーム (2)WSHからバッチを呼び出して、ファイル作成 (2)でファイルが作成はされるのですが、(1)の処理でリネームした ファイルの作成日時(実行時間より古い時間)が入って作成されてしまい、(2)が実行された 日付が入ってくれません。 ちなみに、更新日時アクセス日時は(2)の実行時間が入ります。 環境は以下になります。 OS:Windows7Pro SP1 →この先WindowsSV 2008R2で実行させたいと考えています。 Windowの仕様なのか、どうなのか、わからないのですが どなたか何か回避策をご存じの方がみえれば、ご教授をお願いいたします。 テストで作成したWSHとBatのソースを下記に貼り付けます。 WSH *************************************** option explicit '変数定義 Dim objFso Dim objFile Dim objWShell 'オブジェクトの生成 Set objFso = Wscript.CreateObject("Scripting.FileSystemObject") Set objFile = objFso.GetFile("C:\testDir\File-A.txt") 'ファイル名変更 objFso.GetFile("C:\testDir\File-A.txt").Name = "File-B.txt" 'オブジェクト解放 Set objFile = Nothing 'bat実行 Set objWShell = CreateObject("WScript.Shell") objWShell.Run "C:\testDir\echo.bat", 0, True 'batで作成したFile-Aのオブジェクト生成 Set objFile = objFso.GetFile("C:\testDir\File-A.txt") 'オブジェクト解放 Set objWShell = Nothing Set objFile = Nothing Set objFso = Nothing WSH *************************************** Bat **************************************** echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA > C:\testDir\File-A.txt Bat **************************************** 以上、よろしくお願いします。  

  • 【C言語】引数にファイルパスを送りたい

    DLLで外部のファイルサイズを得る関数を作っています。 C言語は書きながら覚えていこうとしているのですが、 どうしても分からない点がありました。 ソースをここに正しく書ける自信がないので日本語を含めて大体で書きます。 いろいろなサイトのコピペです。 double __stdcall filesize(){ HANDLE hFile; DWORD size; hFile = CreateFile( _T(絶対パス, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); size = GetFileSize( hFile, NULL ); CloseHandle( hFile ); return(size); } このような感じで書いていて最後にretuenでファイルサイズを正しく得ることができました。 この絶対パスは環境によって変わるので引数にしようと考えました。 そしてfilesize()の中にどのように記述すればいいかで躓いています。 filesize(絶対パス){ char pass[] = "絶対パス"; hFile = CreateFile( _T(pass, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); こんな感じで書ければいいのですがC言語はポインタや文字列の扱いが難しいですね。 初歩的なことで申し訳ありませんがよろしくお願いします。

  • WinAPIでのファイル操作について教えて下さい。

    現在参考書やwebサイトと参考にWindowsプログラミングを学んでいます。 下記のサイトにあるファイル作成のソースをコンパイルして実行したのですが http://wisdom.sakura.ne.jp/system/winapi/win32/win111.html #include <windows.h> int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance , PSTR lpCmdLine , int nCmdShow) { HANDLE hFile; hFile = CreateFile( lpCmdLine , GENERIC_READ , 0 , NULL , CREATE_NEW , FILE_ATTRIBUTE_NORMAL , NULL ); if (hFile == INVALID_HANDLE_VALUE) { MessageBox( NULL , TEXT("ファイルを作成できません") , TEXT("エラー") , MB_OK ); return 1; } CloseHandle(hFile); return 0; } コンパイルは成功するのですが実行すると必ずエラーになります。 他のソースも同様にファイル操作に失敗した場合の表示が行われます。 自分が持っている参考書にはファイル操作についてあまり詳しく書かれていないので他のソースも試せません。 どなたか教えて下さいよろしくお願いします。

  • CreateFile が ERROR_PATH_NOT_FOUND のエラーになる

    VC++を使っています。OSは Windows2000 です。 CreateFile で指定するファイル名をフルパスで指定し、EXEを同じ ディレクトリに置いて実行したところエラーとなり、詳細コードが ERROR_PATH_NOT_FOUND でした。 プログラムは以下のようになっています。 #define AAA "c:winnt\\system32\\AAA.log" hOpen = CreateFile( AAA, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 上記プログラムの AAA.exe を system32下に置いて実行すると、 パスが不正だと怒られてしまいます。。。 AAA.exe を別ディレクトリで実行すると、sysytem32下にちゃんと ファイルが作成されます。 AAA.exe を CreateProcess する BBB.exe を造って試しましたが、 やはり BBB.exe が system32下にあると駄目でした。 どうやらカレントディレクトリが同じだと駄目みたいです。 「"AAA.log"」とせずにフルパスとしているのは以下の理由のためです。 ・ファイルは必ず system32下に作成したい。 ・AAA.exe は必ず system32下にある。 しかし、BBB.exe が必ず system32下にあるとは限らないため、 「"AAA.log"」とした場合、BBB.exe を実行したディレクトリに 作成されてしまう。 CreateFile には今回のような制限があるのでしょうか??? #ヘルプを見る限り、書いてないです。。。

  • いやーマイクロソフトには苦労します

    メモ帳で空のファイルx.txtを作り これをGetAttributeでディレクトリかどうかを検査すると x.txtはディレクトリとみなされてしまいます 今x.txtがディレクトリだと動作が異常になる プログラムを作っていたので困っています そこでx.txtを排除するためにサイズを検査して0ならば 処理をしないようにしようと思ったのですが サイズを調べるのに void DispFileSize() { HANDLE hFile; DWORD FileSizeLow, FileSizeHigh; hFile = CreateFile( "\\command.com", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); FileSizeLow = GetFileSize(hFile, &FileSizeHigh); printf("ファイルサイズ: %ud*2^32 + %ud\n", FileSizeHigh, FileSizeLow); CloseHandle(hFile); } などいいう馬鹿らしい処理をしなければなりません しかもこれはディレクトリに適用するものではないのでうまくいくかどうか・・・ ファイルサイズを出すのに簡単にする方法はないのでしょうか? しかしAPIはやたら引数が多いしわけのわからない定数をいっぱい使いますね 泣きたくなります 開発者に問題があるのでしょうね

  • CreateFile関数によるCD/DVDへの書込み方法を教えて下さい

    VCプログラムで、操作履歴情報を出力先ドライブを選択してファイルに保存する機能を作成しています。(OS:Windows-XP) CD-ROM(RW)ドライブを選択すると、以下のエラーになってしまうのですが、 正しい引数または別の方法を教えて頂けませんでしょうか。 ◆エラー ERROR_INVALID_FUNCTION(0x00000001)「ファンクションが間違っています。」 ◆引数 handle = CreateFile( "\\\\.\\E:\\HISmmdd.TXT",// ファイル名 GENERIC_WRITE, // アクセスモード FILE_SHARE_WRITE, // 共有モード NULL, // セキュリティ記述子 CREATE_ALWAYS, // 作成方法 FILE_FLAG_WRITE_THROUGH,// ファイル属性 NULL // テンプレートファイルのハンドル ) ; 以上、宜しくお願い致します!

  • 連番のファイル作成法

    以前にどこかのページで見た連番のファイル作成法ですが、うまくいきません。 $ touch 'jot -w file%03d.txt 999' touch: `jot -w file%03d.txt 999' に touch できません: 許可がありません $ sudo touch 'jot -w file%03d.txt 999' $ ls jot -w file%03d.txt 999 どのようにすれば 001.txt 002.txt ..... 999.txt の999個のファイルが出来上がるようにできますか? どうぞよろしくお願いいたします。

  • 新規でファイルを作成したい

     お世話になっております。  PHPで新規でファイルを作成する方法がうまくいかないのでおしえてください。  fopen関数で、ファイルを開こうとするとき解説書にあるように、「ファイルがなければ新規で作成」というモードを使用しているのですが、このファイルが作成されません。  新規でファイルを作成するモードは、"w" "a" "a+"の筈ですが…。 $temp_file_open = fopen("temp.txt", "w"); flock($temp_file_open, LOCK_EX); $temp_return = fputs($temp_file_open, "$name\n"); flock($temp_file_open, LOCK_UN); fclose($temp_file_open);  このような形で単純に書いているのですが、なかなかうまく行きません。Perlではumaskの設定などが必要ですが、PHPでも必要なのでしょうか?  もし足りない点、または初心者が陥りやすい点を指摘していただけるとありがたいです。

    • ベストアンサー
    • PHP
  • WriteFile関数

    WriteFile関数 C言語でWindowsプログラミングを学習中です。 2点ご質問です。 LPTSTR型のbufferには(1)のように文字列を格納して、 画面に表示しています。 ファイルに保存するために改行は「\r\n」に置き換えているので、 画面上ではもちろん改行されません。 Editコントロールを使用すれば簡単にいくと思いますが、 このような方法で画面上にも改行・ファイルにも改行という方法はありますか? さらに(2)で保存したファイルを開くと文字と文字の間に半角のスペースが 入ってしまいます。 ごくたまに入らない時もありますが、文字列の一部しか表示されません。 これはUNICODEとマルチバイトの関係なのでしょうか? UNICODEを定義しています。 マルチバイトを定義してしまうとGetSaveFileName関数が エラーになってしまうので・・・ ご教授お願いします。 (1) case WM_CHAR: if(wp==VK_BACK){ if(!iCount) return 0; iCount--; InvalidateRect(hWnd,NULL,TRUE); }else if(wp==VK_RETURN){ buffer[iCount++]='\r\n'; InvalidateRect(hWnd,NULL,TRUE); return 0; }else{ buffer[iCount++]=(TCHAR)wp; InvalidateRect(hWnd,NULL,TRUE); } return 0; case WM_PAINT: hdc=BeginPaint(hWnd,&ps); GetClientRect(hWnd,&rc); DrawText(hdc,buffer,iCount,&rc,DT_WORDBREAK); EndPaint(hWnd,&ps); return 0; ・ ・ ・ ・ (2) int MySave(LPTSTR buffer,HWND hWnd) { OPENFILENAME ofn; HANDLE hFile; TCHAR szFile[MAX_PATH]; TCHAR szFileTitle[MAX_PATH]; DWORD dwAccBytes; memset(&ofn,0,sizeof(OPENFILENAME)); ofn.lStructSize=sizeof(OPENFILENAME); ofn.hwndOwner=hWnd; ofn.lpstrFilter=TEXT("text(*.txt)\0*.txt\0All files(*.*)\0*.*\0\0"); ofn.lpstrFile=szFile; ofn.lpstrFileTitle=szFileTitle; ofn.nFilterIndex=1; ofn.nMaxFile=MAX_PATH; ofn.nMaxFileTitle=MAX_PATH; ofn.Flags=OFN_OVERWRITEPROMPT|OFN_HIDEREADONLY; ofn.lpstrDefExt=TEXT("txt"); ofn.lpstrTitle=TEXT("名前を付けて保存"); if(!GetSaveFileName(&ofn)) return -1; hFile=CreateFile(szFile,GENERIC_WRITE,0,NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); WriteFile(hFile,buffer,(DWORD)lstrlen(buffer), &dwAccBytes,NULL); SetWindowText(hWnd,szFileTitle); CloseHandle(hFile); return 0; }

専門家に質問してみよう