概要

コマンドラインで動作し、第一引数で指定されたフォルダー内のファイルについて、日時を修正します。
第一引数のみ指定された場合は、現在の日時。
第二引数で年月日を指定された場合は、指定年月日で時刻は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

 

mtouch.zip