ヨーキョクデイ

100% pure impurities, which may imply some value. (j は虚数単位)

ファイルの最終更新日時をミリ秒単位で取得したい(Windows 限定)

File::Stat#mtime で取得できるファイルの最終更新日時だが、この精度(桁)は実装依存らしく、公式の Ruby では秒単位でしか取得できないものの、JRuby ではミリ秒単位で取得できた。しかし公式実装でもミリ秒単位で取得したいので、Win32 API の力を借りてみることにした。

require 'Win32API'

GENERIC_READ = 0x80000000
OPEN_EXISTING = 3

file = 'E:/o2on/dat/2ch.net/software/1180/1180450101.dat'

create_file = Win32API.new('kernel32', 'CreateFile', 'PIIIIII', 'I')
get_file_time = Win32API.new('kernel32', 'GetFileTime', 'IPPP', 'I')
close_handle = Win32API.new('kernel32', 'CloseHandle', 'I', 'I')
file_time_to_system_time = Win32API.new('kernel32', 'FileTimeToSystemTime', 'PP', 'I')

# 構造体を返してもらう場所を確保
lp_last_write_time = "\0" * 4 * 2  # FILETIME = DWORD * 2
lp_system_time = "\0" * 2 * 8  # SYSTEMTIME = WORD * 8

h_file = create_file.call(file, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)
get_file_time.call(h_file, nil, nil, lp_last_write_time)
close_handle.call(h_file)

file_time_to_system_time.call(lp_last_write_time, lp_system_time)
year, mon, wday, day, hour, min, sec, msec =  lp_system_time.unpack('S8')
p Time.gm(year, mon, day, hour, min, sec, msec * 1000).to_f  # => 1183297724.109


# 普通にやった場合
p File.stat(file).mtime.to_f  # => 1183297724.0

こんな感じだが、速度的にはどうなんだろう。