martin martin - 1 year ago 59
Python Question

Getting last change time in Python on Windows

I have two scripts, one in Python, one in Powershell, that get and compare the last modification of a file. The one in Powershell uses:

$t = $f.LastWriteTime.ToFileTimeUtc()

This time is primary for me and I need to get the same information in Python. I am using
and convert the UNIX timestamp to 'Windows File Time'* using this formula:

statinfo = os.stat(file_name)
t = long(statinfo.st_mtime * 10000000L) + 11644473600L * 10000000L

However, I run into problems with rounding errors.
is a float and when I multiply it and cast to long, I am losing precision -- typically the error is less than 10 (i.e. less then 1 millisecond). I can of course fix my program so that it compares the numbers within this precision, but I would much rather have the same numbers.

There is a similar question on SO here: How do I get *change* file time in Windows? from which I gather I would have to access the structure FILE_BASIC_INFORMATION (, however I am not sure how to do it without using IronPython, PyWin or similar Python extensions. Is there an easy way (maybe using
) to access this information?

*A Windows file time is a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC). See

Answer Source

So, for the benefit of anyone with this problem. Actually, it turns out that the question I mentioned, How do I get *change* file time in Windows?, is a bit misleading, as it mentions an obscure driver access only function ZwQueryInformationFile, while there is plain GetFileTime function you can use. Either way, these functions require file handle and that in turn requires calling CreateFile and CloseHandle and for large number of files (about one million in my case) this is quite expensive. So in the end I used GetFileAttributesExW that only requires path. By my measurements this is still little bit slower (about 10%) than os.stat, which I think is down to the overhead of calling functions through ctypes.

So after some copy-pasting from Internet, I put together the following code that does exactly what I wanted.

from ctypes import windll, Structure, byref
from ctypes.wintypes import LPWSTR, DWORD, FILETIME

class WIN32_FILE_ATTRIBUTE_DATA(Structure):
    _fields_ = [("dwFileAttributes", DWORD),
                ("ftCreationTime", FILETIME),
                ("ftLastAccessTime", FILETIME),
                ("ftLastWriteTime", FILETIME),
                ("nFileSizeHigh", DWORD),
                ("nFileSizeLow", DWORD)]

filename = 'path and file name'

GetFileExInfoStandard = 0
windll.kernel32.GetFileAttributesExW(LPWSTR(filename), GetFileExInfoStandard, byref(wfad))
lowtime = long(wfad.ftLastWriteTime.dwLowDateTime)
hightime = long(wfad.ftLastWriteTime.dwHighDateTime)
filetime = (hightime << 32) + lowtime
print filetime