山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他フォルダー内のファイル日付修正
概要
コマンドラインで動作し、第一引数で指定されたフォルダー内のファイルについて、日時を修正します。
第一引数のみ指定された場合は、現在の日時。
第二引数で年月日を指定された場合は、指定年月日で時刻は0時0分0秒
第二引数で年月日、第三引数で時刻を指定された場合は、指定日時に修正します。
なお、FAT12,FAT16,FAT32の場合は、ファイルシステムが1秒単位で保存できないため、2秒単位となります。
また、作成日時、アクセス日時についてはFAT12,FAT16,FAT32では必須でないためサポートされないことが多いようです。したがって、修正してもそのとおりとならないことが多いです。
Visual C++ 2008 Standard Edition 32/64bit対応
使い方の例
カレントフォルダのtestフォルダ内のファイルを現在日時に修正する。
mtouch test
カレントフォルダのtestフォルダ内のファイルを指定年月日に修正する。
mtouch test 2000/1/1
カレントフォルダのtestフォルダ内のファイルを指定年月日に指定時刻に修正する。
mtouch test 2000/1/1 1:2:3
プログラム説明
全体の流れ
コマンドラインの引数を解析し、修正するローカルタイム日時を構造体SYSTEMTIME stに保存します。
indFirstFile及びFindNextFile APIでフォルダー内のファイルを検索し、ファイルのリストを作成します。ファイル検索後はCloseHandleを実行します。
検索されたファイルは、CreateFileでハンドルを取得し、SetFileTime APIで日時を修正し、CloseHandleを実行します。
ファイル日時の取得
ファイル日時を取得する場合は、ファイルのオープン後にGetFileTime APIまたは、FindFirstFile及びFindNextFileで取得できます。
GetFileTimeで取得する場合は、FILETIME(1601 年 1 月 1 日午前 12 時からの 100 ナノ秒間隔の数を表す 64 ビット値でUTC)であるため、これをFILETIMEのローカルタイムに変換し、さらにSYSTEMTIME構造体で年月日を個別に得ることができます。
GetFileTime(hFile,&CreationTime,&AccessTime,&WriteTime);
FileTimeToLocalFileTime(&CreationTime,&localTime); // UTC→ローカルタイム
FileTimeToSystemTime(&localTime,&systemTime); // FILETIMEをSYSTEMTIMEに変換
printf("\tCreationTime %i/%i/%i %i:%i:%i\n",systemTime.wYear,systemTime.wMonth,systemTime.wDay,systemTime.wHour,systemTime.wMinute,systemTime.wSecond);
ファイル日時の修正
ファイル日時を修正するためには、SetFileTime APIを使いますが、引数がFILETIME(1601 年 1 月 1 日午前 12 時からの 100 ナノ秒間隔の数を表す 64 ビット値でUTC)であるため、まずローカルタイムからFILETIMEを作成し、これをUTCに変換します。
SYSTEMTIME st;
printf("変更後 Create,Write,Access %i/%i/%i %i:%i:%i\n",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);
if(SystemTimeToFileTime(&st,&localTime)==0){ // SYSTEMTIMEをFILETIMEに変換
puts("\tSystemTimeToFileTime API error");
}
if(LocalFileTimeToFileTime(&localTime,&AccessTime2)==0){ // ローカルタイム→UTC
puts("\tLocalFileTimeToFileTim API error");
}
SetFileTime(hFile,&AccessTime2,&AccessTime2,&AccessTime2);
mtouch.cpp
// 指定されたフォルダーに存在するファイルの日付を変更する。
// Visual C++ 2008 コマンドライン用
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <time.h>
#include "list.hpp"
struct FILE_LINK{
TCHAR* name; // ファイル名
FILE_LINK* next; // 次のファイル名へのポインタ
FILE_LINK(){
name=0;
next=0;
}
};
struct FILE_LIST : public LIST{
void append(FILE_LINK* p){
LIST::append((void*)p);
}
FILE_LINK* next(void){
return (FILE_LINK*)LIST::next();
}
FILE_LINK* first(void){
return (FILE_LINK*)LIST::first();
}
};
time_t get_now_time(tm& now_tm ); // 現在の時刻を取得(ローカルタイム)
void tm_to_systemtime(struct tm& stm,SYSTEMTIME& st); // 構造体tmを構造体SYSTEMTIMEに変換する
int get_dir_list(FILE_LIST& list,TCHAR* pass,TCHAR* card); // サブディレクトリ内の指定ファイルを検索する
bool atodate(TCHAR* s,SYSTEMTIME& t); // 文字列を日付に変換する。 文字列例 2004/12/12
bool atotime(TCHAR* s,SYSTEMTIME& t); // 文字列を時刻に変換する。 文字列例 12:12:12
int file_time_touch(TCHAR* file_name,FILETIME& AccessTime2); // 指定されたファイルの日付を変更する
int _tmain(int argc, TCHAR** argv){
TCHAR* pass;
char sjis[MAX_PATH*4];
TCHAR FullPath[MAX_PATH*2];
TCHAR* FilePart;
tm now_tm;
SYSTEMTIME st;
FILETIME localTime;
FILETIME AccessTime2;
switch(argc){
case 1:
puts("使い方\nmtouch フォルダー名 [日付] [時刻]\n[]内は省略可能\n使用例\nmtouch d:\\ 2011/1/1 12:00:00\n");
exit(1);
break;
case 2: // フォルダー名のみ指定されている場合 現在の日付で時刻は0:0:0とする。
pass=argv[1];
get_now_time(now_tm); // 現在時刻をローカルタイムで取得
tm_to_systemtime(now_tm,st);
st.wHour=0;
st.wMinute=0;
st.wSecond=0;
st.wMilliseconds=0;
break;
case 3: // フォルダー名および日付が指定されている場合 指定された日付で時刻は0:0:0とする。
pass=argv[1];
if(atodate(argv[2],st)==false){
puts("日付の指定が正しくありません。");
exit(2);
}
st.wHour=0;
st.wMinute=0;
st.wSecond=0;
st.wMilliseconds=0;
break;
case 4:
pass=argv[1];
if(atodate(argv[2],st)==false){
puts("日付の指定が正しくありません。");
exit(2);
}
if(atotime(argv[3],st)==false){
puts("時刻の指定が正しくありません。");
exit(2);
}
break;
}
printf("変更後 Create,Write,Access %i/%i/%i %i:%i:%i\n",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);
if(SystemTimeToFileTime(&st,&localTime)==0){ // SYSTEMTIMEをFILETIMEに変換
puts("\tSystemTimeToFileTime API error");
}
if(LocalFileTimeToFileTime(&localTime,&AccessTime2)==0){ // ローカルタイム→UTC
puts("\tLocalFileTimeToFileTim API error");
}
GetFullPathName(pass,sizeof(FullPath)/sizeof(TCHAR),FullPath,&FilePart); //絶対パスに変更
if(FilePart==NULL){
FullPath[_tcslen(FullPath)-1]=_T('\0'); // ルートディレクトリが指定された場合は\を削除する
}
int n=0; // ファイル番号
FILE_LIST file_list;
get_dir_list(file_list,FullPath,TEXT("*.*"));
int num=file_list.get_max(); // ファイル数
FILE_LINK* p;
n=0;
p=file_list.first();
while(p){
WideCharToMultiByte(932,0,p->name,-1,sjis,sizeof(sjis),NULL,NULL);
puts(sjis);
file_time_touch(p->name,AccessTime2);
p=file_list.next();
}
printf("%i個のファイルを変更しました。\n",num);
return 0;
}
// 現在の時刻を取得(ローカルタイム)
time_t get_now_time(tm& now_tm ){
time_t now_time_t;
tm lim_tm;
time(&now_time_t);
errno_t err;
err=localtime_s(&now_tm,&now_time_t);
gmtime_s(&lim_tm,(time_t*)&now_time_t);
return now_time_t;
}
// 構造体tmを構造体SYSTEMTIMEに変換する
void tm_to_systemtime(struct tm& stm,SYSTEMTIME& st){
st.wYear=stm.tm_year+1900;
st.wMonth=stm.tm_mon+1;
st.wDay=stm.tm_mday;
st.wDayOfWeek=stm.tm_wday;
st.wHour=stm.tm_hour;
st.wMinute=stm.tm_min;
st.wSecond=stm.tm_sec;
st.wMilliseconds=0;
}
// サブディレクトリ内の指定ファイルを検索する
int get_dir_list(FILE_LIST& list,TCHAR* pass,TCHAR* card){
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
TCHAR find_pass[MAX_PATH];
TCHAR make_pass[MAX_PATH];
int num=0; // 見つかったファイル数
_stprintf_s(find_pass,sizeof(find_pass)/sizeof(TCHAR),TEXT("%s\\%s"),pass,card); // ファイルの検索
hFind = FindFirstFile(find_pass, &FindFileData);
if(hFind != INVALID_HANDLE_VALUE){
do{
if( !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
++num;
_stprintf_s(make_pass,sizeof(make_pass)/sizeof(TCHAR),TEXT("%s\\%s"),pass,FindFileData.cFileName);
size_t len=_tcslen(make_pass);
TCHAR* n=new TCHAR[len+1];
_tcscpy_s(n,len+1,make_pass);
FILE_LINK* p=new FILE_LINK;
p->name=n;
p->next=0;
list.append(p);
}
}while(FindNextFile(hFind,&FindFileData));
CloseHandle(hFind);
return num;
}else
return num;
}
// 文字列を日付に変換する。 文字列例 2004/12/12
bool atodate(TCHAR* s,SYSTEMTIME& t){
TCHAR* p =s;
TCHAR* tp=s;
int n=0;
TCHAR* wp[4];
wp[0]=s;
while(*s){
if(*s==_T('/')){
*s=_T('\0');
wp[n++]=tp;
tp=s+1;
}
if(n==4)
return false;
++s;
}
if(n==2){
t.wYear=_ttoi(wp[0]);
t.wMonth=_ttoi(wp[1]);
t.wDay=_ttoi(tp);
return true;
}else
return false;
}
// 文字列を時刻に変換する。 文字列例 12:12:12
bool atotime(TCHAR* s,SYSTEMTIME& t){
TCHAR* p =s;
TCHAR* tp=s;
int n=0;
TCHAR* wp[4];
wp[0]=s;
while(*s){
if(*s==_T(':')){
*s= _T('\0');
wp[n++]=tp;
tp=s+1;
}
if(n==4)
return false;
++s;
}
switch(n){
case 2:
t.wHour=_ttoi(wp[0]);
t.wMinute=_ttoi(wp[1]);
t.wSecond=_ttoi(tp);
t.wMilliseconds=0;
return true;
case 1:
t.wHour=_ttoi(wp[0]);
t.wMinute=_ttoi(tp);
t.wSecond=0;
t.wMilliseconds=0;
return true;
case 0:
t.wHour=_ttoi(tp);
t.wMinute=0;
t.wSecond=0;
t.wMilliseconds=0;
return true;
default:
return false;
}
}
// 指定されたファイルの日付を変更する
int file_time_touch(TCHAR* file_name,FILETIME& AccessTime2){
HANDLE hFile;
hFile=CreateFile(file_name,GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile==INVALID_HANDLE_VALUE){
puts("\tFile Open Error");
return -1;
}
FILETIME CreationTime;
FILETIME AccessTime;
FILETIME WriteTime;
FILETIME localTime;
SYSTEMTIME systemTime;
// 現在のファイルの日時を取得表示
GetFileTime(hFile,&CreationTime,&AccessTime,&WriteTime);
FileTimeToLocalFileTime(&CreationTime,&localTime); // UTC→ローカルタイム
FileTimeToSystemTime(&localTime,&systemTime); // FILETIMEをSYSTEMTIMEに変換
printf("\t変更前 Create %i/%i/%i %i:%i:%i\n",systemTime.wYear,systemTime.wMonth,systemTime.wDay,systemTime.wHour,systemTime.wMinute,systemTime.wSecond);
SystemTimeToFileTime(&systemTime,&localTime); // SYSTEMTIMEをFILETIMEに変換
LocalFileTimeToFileTime(&localTime,&CreationTime); // ローカルタイム→UTC
FileTimeToLocalFileTime(&WriteTime,&localTime); // UTC→ローカルタイム
FileTimeToSystemTime(&localTime,&systemTime); // FILETIMEをSYSTEMTIMEに変換
printf("\t変更前 Write %i/%i/%i %i:%i:%i\n",systemTime.wYear,systemTime.wMonth,systemTime.wDay,systemTime.wHour,systemTime.wMinute,systemTime.wSecond);
SystemTimeToFileTime(&systemTime,&localTime); // SYSTEMTIMEをFILETIMEに変換
LocalFileTimeToFileTime(&localTime,&WriteTime); // ローカルタイム→UTC
FileTimeToLocalFileTime(&AccessTime,&localTime); // UTC→ローカルタイム
FileTimeToSystemTime(&localTime,&systemTime); // FILETIMEをSYSTEMTIMEに変換
printf("\t変更前 Access %i/%i/%i %i:%i:%i\n",systemTime.wYear,systemTime.wMonth,systemTime.wDay,systemTime.wHour,systemTime.wMinute,systemTime.wSecond);
if(SetFileTime(hFile,&AccessTime2,&AccessTime2,&AccessTime2)==0){
puts("\tSetFileTime API error");
CloseHandle(hFile);
return -2;
}
CloseHandle(hFile);
return 0;
}
list.hpp
#ifndef LIST_HPP
#define LIST_HPP 1
class LINK{
LINK* next;
LINK* back;
void* data;
protected:
LINK(){
next=0;
back=0;
data=0;
}
void set(void* d){
data=d;
}
friend class LIST;
friend int cmp(const void* d,const void* s){
if((char*)d>(char*)s)
return 1;
if((char*)d<(char*)s)
return -1;
return 0;
}
};
typedef void* LPVOID;
class LIST{
LINK* top; // リストの先頭
LINK* end; // リストの最後尾
LINK* pos; // リストのカレントポジション
int max; // リストの要素数
protected:
LIST(){
pos=top=end=0;
max=0;
}
void append(void* d){ // リストの最後尾にデータを追加
LINK* p=new LINK;
++max;
p->data=d;
if(top==0){
pos=top=end=p;
}else{
end->next=p;
p->back=end;
end=p;
}
}
void* next(void){ // カレントポジジョンからデータを得た後、カレントポジションを1個進める。
LINK* t=pos;
if(pos==0){
return 0;
}else{
pos=pos->next;
return t->data;
}
}
void* first(void){ // カレントポジションを先頭に移動させ先頭データを得た後、カレントポジションを1個進める。
pos=top;
return next();
}
void all_del(void){ // リスト全部を削除する
while(top){
LINK* t=top->next;
delete top;
top=t;
}
top=end=pos=0;
max=0;
}
void repeat_del(int(*cmp )(const void* d,const void* s)){ // ソートされたリストから重複する要素を削除
LINK* lp=top;
if(lp){
LINK* bp=0;
while(lp){
if(bp){
if( (*cmp)((void**)&lp->data,(void**)&bp->data) ){ // 前の要素と異なる場合
bp=lp;
}else{ // 前の要素と同じ場合
LINK* t=lp->next;
del(lp);
--max;
lp=t;
continue;
}
}else
bp=lp;
lp=lp->next;
}
}
}
void qsort(int(*cmp )(const void* d,const void* s)){
if(max){
int n=0;
LPVOID* vec=new LPVOID[max]; // リストの要素を配列にコピーする
if(vec==0)
return;
void* p;
p=first();
while(p){
vec[n++]=p;
p=next();
}
::qsort((void*)vec,max,sizeof(LPVOID),cmp);
LINK* lp=top; // 配列をリストにコピー
n=0;
while(lp){
lp->set(vec[n++]);
lp=lp->next;
}
delete vec;
}
}
void del(LINK* p){ // リストからpを削除する
if(p){
if(p==top){
LINK* t=top;
top=top->next;
top->back=0;
if(pos==p){
pos=p->next;
}
delete p;
return;
}
if(p==end){
LINK* t=end;
end=end->back;
end->next=0;
delete p;
return;
}
LINK* t=p;
p->back->next=p->next;
p->next->back=p->back;
if(pos==p){
pos=p->next;
}
delete t;
}
}
public:
int get_max(void){
return max;
}
};
#endif