汇编(ASM)中如何判断文件时长?任务场景与代码求助
问题描述
我正在完成一个任务:用GetOpenFileName选择文件,判断文件是否创建时间小于3天,若是则读取文件内容;否则弹出对话框询问是否删除,用户确认就删除。要求用到的结构要放在动态分配的内存中。
目前已经实现了文件打开功能,但不知道怎么判断文件时长。我初步想的是用GetFileTime获取文件时间,转成本地时间再转成系统时间,之后做减法判断,但具体操作不清楚,也想知道有没有替代方法。
现有代码
File.inc
include WINDOWS.inc include user32.inc include kernel32.inc include comdlg32.inc includelib user32.lib includelib kernel32.lib includelib comdlg32.lib .data Time_title db ' Lab_3',0 format db 'More than 3 days. Delete file?', 0 buf db 255 dup(0) hFile dd 0 readed dd 0 hmem dd 0
File.asm
.386 .model flat,STDCALL option casemap :none ;区分大小写 include Third.inc include RADbg.inc Mem_Alloc PROC Buf_Size:DWORD add Buf_Size,4 invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,Buf_Size push eax invoke GlobalLock,eax pop [eax] add eax,4 Mem_Alloc endp Mem_Free PROC DATA:DWORD mov eax,DATA sub eax,4 mov eax,[eax] push eax push eax call GlobalUnlock call GlobalFree Mem_Free endp .code Begin: call main invoke ExitProcess,NULL main proc LOCAL ftCreate, ftLocale: FILETIME; LOCAL stUTC, stLocal: SYSTEMTIME; invoke Mem_Alloc, 1000h mov hmem, eax invoke Mem_Alloc, sizeof OPENFILENAME mov edi, eax assume edi: ptr OPENFILENAME xor eax, eax mov [edi].lStructSize, sizeof OPENFILENAME mov [edi].lpstrFile, offset buf mov [edi].nMaxFile, 255 invoke GetOpenFileName, edi invoke CreateFile, [edi].lpstrFile, GENERIC_READ,\ FILE_SHARE_READ, NULL, OPEN_EXISTING,\ FILE_ATTRIBUTE_NORMAL, NULL mov hFile,eax ;保存文件句柄 invoke GetFileTime, hFile, addr ftCreate, NULL, NULL invoke FileTimeToLocalFileTime, addr ftCreate, addr ftLocale invoke FileTimeToSystemTime, addr ftCreate, addr stUTC cmp eax, 1 jz l1 invoke ReadFile, hFile, hmem, 1000h, addr readed, 0 invoke MessageBox, 0, hmem, addr Time_title, MB_OKCANCEL jmp l2 l1: invoke MessageBox, 0, addr format, addr Time_title, MB_OKCANCEL cmp eax, IDOK jne l2 invoke DeleteFile, addr [edi].lpstrFile l2: assume edi: dword invoke CloseHandle, hFile invoke Mem_Free, hmem invoke Mem_Free, edi ret main endp end Begin
解决方法
方法1:直接计算FILETIME时间差(推荐)
FILETIME结构存储的是自1601年1月1日以来的100纳秒数,所以可以直接计算当前时间和文件创建时间的差值,判断是否超过3天的总纳秒数。
3天的总100纳秒数计算:3天 = 32460*60秒 = 259200秒,乘以107(因为1秒=107个100纳秒),得到2592000000000。
修改main proc中的代码,添加获取当前系统时间并转成FILETIME的步骤:
main proc LOCAL ftCreate, ftNow, ftDiff: FILETIME; LOCAL stNow: SYSTEMTIME; ; ... 保留原有文件选择、打开代码 ... invoke GetFileTime, hFile, addr ftCreate, NULL, NULL ; 获取当前系统时间并转成FILETIME invoke GetLocalTime, addr stNow invoke SystemTimeToFileTime, addr stNow, addr ftNow ; 计算时间差:当前时间 - 文件创建时间 mov eax, ftNow.dwLowDateTime sub eax, ftCreate.dwLowDateTime mov ftDiff.dwLowDateTime, eax mov eax, ftNow.dwHighDateTime sbb eax, ftCreate.dwHighDateTime mov ftDiff.dwHighDateTime, eax ; 判断时间差是否超过3天(2592000000000个100纳秒) mov eax, ftDiff.dwHighDateTime cmp eax, 00000000h ; 高32位如果大于0,肯定超过3天 jg l1 mov eax, ftDiff.dwLowDateTime cmp eax, 2592000000000h jge l1 ; 文件创建时间小于3天,执行读取逻辑 invoke ReadFile, hFile, hmem, 1000h, addr readed, 0 invoke MessageBox, 0, hmem, addr Time_title, MB_OKCANCEL jmp l2 l1: ; 文件超过3天,询问删除 invoke MessageBox, 0, addr format, addr Time_title, MB_OKCANCEL cmp eax, IDOK jne l2 invoke DeleteFile, addr [edi].lpstrFile l2: ; ... 保留原有资源释放代码 ... ret main endp
方法2:通过SYSTEMTIME计算日期差
如果一定要用SYSTEMTIME进行日期计算,需要把文件创建时间和当前时间转成SYSTEMTIME后,手动计算日期差值:
main proc LOCAL ftCreate, ftLocale: FILETIME; LOCAL stFile, stNow: SYSTEMTIME; ; ... 保留原有文件选择、打开代码 ... invoke GetFileTime, hFile, addr ftCreate, NULL, NULL invoke FileTimeToLocalFileTime, addr ftCreate, addr ftLocale invoke FileTimeToSystemTime, addr ftLocale, addr stFile invoke GetLocalTime, addr stNow ; 计算日期差:当前日期 - 文件创建日期 mov eax, stNow.wYear sub eax, stFile.wYear mov ecx, eax imul ecx, 365 mov eax, stNow.wMonth sub eax, stFile.wMonth imul eax, 30 ; 简化计算,忽略月份天数差异 add ecx, eax mov eax, stNow.wDay sub eax, stFile.wDay add ecx, eax ; 判断是否超过3天 cmp ecx, 3 jge l1 ; 读取文件逻辑 invoke ReadFile, hFile, hmem, 1000h, addr readed, 0 invoke MessageBox, 0, hmem, addr Time_title, MB_OKCANCEL jmp l2 l1: ; 删除询问逻辑 invoke MessageBox, 0, addr format, addr Time_title, MB_OKCANCEL cmp eax, IDOK jne l2 invoke DeleteFile, addr [edi].lpstrFile l2: ; ... 保留原有资源释放代码 ... ret main endp
注意:这种方法是简化计算,没有考虑闰年、不同月份天数不同的情况,精度不如FILETIME直接计算。
内容的提问来源于stack exchange,提问作者Sollpix
相关产品推荐
相关产品推荐

