Windows のファイルには、 そのファイルを作成した「作成日時」、 そのファイルを最後に更新した「更新日時」、 そしてそのファイルに最後にアクセスした「アクセス日時」の 3 種類のタイムスタンプが付いています。
これらのタイムスタンプはファイルに書き込まれたデータではありませんので、 ファイル操作によって変更することはできません。
以前は CD とか DVD にプログラムファイルやデータを書き込むときに、 リリース日の 0 時 0 分 0 秒に揃えるなどしていましたが、 今は物理的なメディアでファイルをやりとりすることもほぼなくなり、 しばらくの間、忘れていました。
今回ちょっと調べたいことがあったのでタイムスタンプを操作したかったのですが、 当時どうやっていたかは覚えていませんので、調べ直しました。
ここでは MFC を利用した C++ プログラムからタイムスタンプを変更するコードについて、書いています。
なお、本サイトのご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。
投稿 February 24, 2022
3 種類あるタイムスタンプは、いずれもファイルに書き込まれているわけではありません。
簡単に確認するには、試しに
作成したてのファイルですので、作成日時、更新日時、アクセス日時とも同じになっています。 ファイルサイズは 0 バイトですが、タイムスタンプは表示されています。
作成したテキストファイルをメモ帳で開き、1 文字記入して上書き保存すると、ファイルが更新されます。
作成日時は変わりませんが、更新日時とアクセス日時は更新されています。
このところ小さいデータファイルを調べていて気になったのですが、 不思議なことに「ディスク上のサイズ」が 0 バイトとなっています。 どこに書かれているのか、四捨五入みたいな表示なのか、ついでに確認しておきます。
とりあえずファイル名でレジストリを検索しましたが、見つかりませんでした。 一定のサイズより小さいファイルデータをレジストリに置いていたら、レジストリが大きくなりすぎますね。
表示上の問題だけでしょうか?
徐々にテキストファイルのサイズを大きくしてプロパティを見てみます。
改行コード 2 バイトを含め 36 バイトにしてみても、ディスク上のサイズは 0 のままでした。
増やして 126 バイトにしても、0 のままでした。
さらに増やして 270 バイトにしても、0 のままでした。
倍の 540 バイトにしても 0 のままで、
1 KB を超えた 1,080 バイトにすると、
おそらく
少しづつ減らして 540 バイトまで戻りましたが、ディスク上のサイズは 4.00 KB になっています。 さらに減らして 1 バイトでもディスク上のサイズは 4.00 KB なのですが、 0 にしたら 0 となり、再び 1 文字加えて 1 バイトにしても、ディスク上のサイズは 0 のまま表示されました。
エクスプローラーの表示の問題、ということでいいのでしょうか? 0 バイトでリセットされるものの、最後の状態がベースとなる、ということでいいのでしょうか?
投稿 February 24, 2022
ここでは Visual C++ で
CFileStatus fs; CFile::GetStatus(_T("TargetFile.txt"), fs)
GetStatus 関数は CFile クラスにスタティックで定義されていますので、 このように呼び出せば、CFileStatus 構造体に定義された情報が得られます。
CFileStatus 構造体には、CTime クラスで表されるタイムスタンプ情報が含まれています。
fs.m_ctime が作成日時を、 fs.m_mtime が更新日時を、 そして fs.m_atime がアクセス日時を保持しています。
CTime クラスが取り出し関数を持っていますので、次のように日時を取り出せます。
CString str; CTmie tm = m_fs.m_ctime; str.Format(_T("%d年 %d月 %d日、%02d:%02d:%02d"), tm.GetYear(), tm.GetMonth(), tm.GetDay(), tm.GetHour(), tm.GetMinute(), tm.GetSecond());
タイムスタンプとしては秒単位までしかありません。 CTime には SYSTEMTIME 構造体に変換する関数が用意されていますが、ミリ秒は 0 になっていました。
投稿 February 24, 2022
書き換えも、簡単です。
CFileStatus fs; // fs に希望の値を設定する CFile::SetStatus(_T("TargetFile.txt"), fs);
タイムスタンプ部分だけを書き換えたくても SetStatus 関数に設定や除外を指示するフラグはありませんので、 直前に GetStatus 関数で CFileStatus を取得して、 必要な部分だけ書き換えて、それを書き込むといいと思います。
タイムスタンプの書き換えは、例えば作成日時なら、次のようでいいでしょう。
fs.m_ctime = CTime(nYear, nMonth, nDay, nHour, nMinute, nSecond);
nYear や nMonth などは設定したい日時が入った int 値ですが、 直接数値をここに書いても問題ありません。 CTime クラスのオブジェクトを作成し、それを m_ctime メンバに代入している、ということになります。
3 種類すべて書き換えたい場合は、同様に m_mtime と m_atime を設定し、 SetStatus 関数で記録すればよいでしょう。
投稿 February 24, 2022
とりあえず動作を試すのに、ファイルを決め打ちなのは面白くありませんが、 ファイル選択ダイアログで選択するのも面倒です。 ダイアログを作成し、ファイルのドロップを受け入れるのが簡単です。
Visual Studio で、Ctrl + Shift + X キーでクラスウィザードを開き、 「クラス名」の欄に目的のダイアログが指定されていることを確認してから、 「メッセージ」タブの WM_DROPFILES のハンドラーを追加します。
このメッセージを発行させるため、ダイアログの Accept Files プロパティを True に設定することを忘れてはいけません。 このプロパティが設定されていない場合は、OnDropFiles ハンドラーを作成しても、呼び出されることはありません。
void CSAChangeTimestampDlg::OnDropFiles(HDROP hDropInfo) { UINT unNumDropped; // ドロップされたファイル数 TCHAR szBuffer[MAX_PATH]; CString strFile; // ターゲットファイル情報をクリアしておきます。 strFile.Empty(); // ドロップされたファイル数を検査します。 unNumDropped = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0); if (unNumDropped < 1) { // ドロップファイルなし return; } if (unNumDropped > 1) { // 2つ以上ドロップ? MessageBox(_T("2つ以上のファイルがドロップされましたが、\n1つのみが有効です。"), NULL, MB_ICONEXCLAMATION | MB_OK); return; } // ターゲットファイル名(ドロップファイル)を取得します。 for (UINT i = 0; i < unNumDropped; i++) { DragQueryFile(hDropInfo, i, szBuffer, MAX_PATH); // ファイル名を取得 strFile.Format(_T("%s"), szBuffer); // 対象となる処理を入れます } }
デフォルトの処理、
CDialogEx::OnDropFiles(hDropInfo);
は、行わなくてよいと思います。
ここでは 1 ファイルだけを対象としたいので、2 ファイル以上のドロップではメッセージを表示しています。 続く for ループは、unNumDropped まで行う意味がありませんが、 複数ファイルをドロップした場合の処理として、あえて残しています。
投稿 February 24, 2022
ここで用意した SAChangeTimestamp.exe は、単体で動作する 32 ビットプログラムです。
zip 圧縮したファイルは、次の URL に置いていますので、下記文字列をブラウザの URL 欄に入力して、ダウンロード可能です。
https://www.straightapps.com/download/SAChangeTimestamp.zip
正しい zip ファイルのタイムスタンプは 2022/2/24 15:17:05、 正しい実行ファイルのタイムスタンプ(更新日時)は 2022/2/24 15:09:53 で、 zip 内は実行ファイル1つだけです。 zip ファイルサイズは 1,946,496 バイト、 実行ファイルのサイズは 3,565,056 バイトです。 パスワードは設定していません。
私なら、完全に信用できるサイト以外からのダウンロードはしませんが、
興味がある方のために、実行ファイルを圧縮したものを置いています。
安全に努めているマシンで用意したファイルですが、お試しいただく場合は、完全に自己責任でお願いします。
OSは Windows 7 以降、ランタイムなど環境の用意は
ダイアログにファイルをドロップすると、そのファイル名が上部に表示され、 作成日時、更新日時、アクセス日時を取得して表示します。
ラジオボタンで日時の種類を選択すると、下の入力欄に表示されますので、 好きな日時に編集して、「変更を適用」をクリックすると、書き込まれます。 3 種類の日付を一度に変更したい場合は、「すべてに適用」をクリックします。
「再読み込み」ボタンは、変更したあとなどに日時情報を読み直す時に使います。
「現在の日時を設定」をクリックすると、入力欄の日時が現在のものになります。 入力欄が変更されるだけですので、ファイル情報は変更されません。
改めて、利用はあくまで自己責任でお願いします。 不具合による損害等があっても、当サイトは一切責任を持ちません。
Windows 開発トップ
Windows 開発関連の情報を、書いています。
おすすめ記事はありません。