사용자 도구

사이트 도구


kb:windowsfiletime

Windows File Time

파일 시간… 뭔가 여러 가지로 복잡하다. 정리해 보자면 다음과 같다.

종류 의미
System Time UTC (Coordinated Universal Time) 기반 타임. 아마 영국 그리니치 어딘가가 기준이였지.
Local Time System Time 에다 타임존 값과 DST(Daylight Saving Time) 값을 더하고 뺀 값.
File Time Create, Last Access, Last Write 값이 있는데, 문제는 파일 시스템마다 이 값을 저장하는 방식이 틀리다는 것.

NTFS에서는 UTC, 즉 위에서 언급한 System Time 형식으로 파일 타임을 저장한다.

FAT에서는 Local Time 형식으로 파일 타임을 저장한다.
Dos File Time 16비트 파일 타임

FAT 상에 있는 파일이랑, NTFS 상에 있는 파일을 비교할 때는 뭐가 어떻게 돌아가는 거냐!

마지막으로 수정한 시간 알아내기

생성 시간도 있고, 액세스 시간도 있지만, 주로 사용하는 건 마지막으로 수정한 시간(Last Write Time)이다.

일단 MSDN에 나와있는 샘플을 기본으로 만든 소스… 이 방식이 표준이라고 생각하면 된다. (과연?)

string getLastWriteTime(const string& filename)
{
    HANDLE hFile = ::CreateFile(filename.c_str(), 
        GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
 
    if (hFile == INVALID_HANDLE_VALUE) return "";
 
    FILETIME ftCreate, ftAccess, ftWrite;
    SYSTEMTIME stUTC, stLocal;
 
    // 파일 타임을 얻어낸다.
    if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
    {
        ::CloseHandle(hFile);
        return "";
    }
 
    // 마지막 수정 시간을 로컬 타임으로 변환한다.
    FileTimeToSystemTime(&ftWrite, &stUTC);
    SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
 
    // 문자열로 변환한다.
    char buf[256] = {0,};
    sprintf(buf, "%d/%02d/%02d  %02d:%02d:%02d",
        stLocal.wYear, stLocal.wMonth, stLocal.wDay,
        stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
 
    ::CloseHandle(hFile);
 
    return buf;
}

Zip 라이브러리 제작할 때 사용한 소스… 다른 건 아니고, WORD 형으로 된 날짜와 시간이 필요하기 때문이다. 그리고 원인은 잘 모르겠으나, 위의 버전과 2초씩 차이가 날 때가 있다. 안 날 때도 있고… ㅡㅡ;

string getLastWriteTime(const string& filename)
{
    WIN32_FIND_DATA ff32;
    FILETIME ftWrite;
 
    HANDLE hFind = ::FindFirstFile(filename.c_str(), &ff32);
    if (hFind == INVALID_HANDLE_VALUE) return "";
 
    // 마지막 수정 시간을 복사한다.
    ::FileTimeToLocalFileTime(&(ff32.ftLastWriteTime), &ftWrite);
 
    // 핸들 닫아주고...
    ::FindClose(hFind);
 
    struct DOS_DATE
    {
        unsigned day   : 5;
        unsigned month : 4;
        unsigned year  : 7;
    };
 
    struct DOS_TIME
    {
        unsigned second : 5;
        unsigned minute : 6;
        unsigned hour   : 5;
    };
 
    DOS_DATE dos_date;
    DOS_TIME dos_time;
    char buf[256] = {0,};
 
    // 도스 타임으로 변환한다.
    FileTimeToDosDateTime(&ftWrite, 
        reinterpret_cast<WORD*>(&dos_date), 
        reinterpret_cast<WORD*>(&dos_time));
 
    // 문자열로 변환한다.
    sprintf(buf, "%4d/%02d/%02d  %02d:%02d:%02d", 
        dos_date.year + 1980, dos_date.month, dos_date.day,
        dos_time.hour, dos_time.minute, dos_time.second * 2);
 
    return buf;
}

스탠다드 라이브러리의 stat 함수를 사용한 소스. 함수 시그너쳐가 유닉스 계열과는 약간 틀리니 주의…

...
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
 
string getLastWriteTime(const string& filename)
{
    struct __stat64 fs;
 
    int result = _stat64(filename.c_str(), &fs);
    if (result != 0) return "";
 
    struct tm* ftWrite = _localtime64(&fs.st_mtime);
    if (ftWrite == NULL) return "";
 
    char buf[256] = {0,};
    sprintf(buf, "%4d/%02d/%02d  %02d:%02d:%02d", 
        ftWrite->tm_year + 1900, ftWrite->tm_mon + 1, ftWrite->tm_mday,
        ftWrite->tm_hour, ftWrite->tm_min, ftWrite->tm_sec);
 
    return buf;
}

링크

kb/windowsfiletime.txt · 마지막으로 수정됨: 2014/11/09 20:39 (바깥 편집)