找回密码
 加入
搜索
查看: 2782|回复: 3

[系统综合] 有办法在监视文件系统时判断文件已经创建完毕吗??

[复制链接]
发表于 2013-2-6 23:17:37 | 显示全部楼层 |阅读模式
目前使用的是这段代码来监视文件系统的,可是发现的问题是,当创建一个比较大的新文件时似乎没法判断文件是否已经创建完毕,,请问有什么好办法么?
#cs ----------------------------------------------------------------------------

    AutoIt Version: 3.3.6.1
    Author:         zorphnog (M. Mims)
    Modified:       Jackchen

    Script Function:
    Monitors the user defined directories for file activity.

#ce ----------------------------------------------------------------------------



Global $bMonitoring = False
AutoItSetOption("GUIOnEventMode", 1)

$gFileMon = GUICreate("Directory Monitor", 731, 385, 194, 126)
GUISetOnEvent($GUI_EVENT_CLOSE, "_OnEvent_Close")
GUICtrlCreateGroup("Monitored Directories", 8, 0, 713, 105)
$btAdd = GUICtrlCreateButton("Add", 16, 24, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Add")
$btRemove = GUICtrlCreateButton("Remove", 16, 56, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Remove")
GUICtrlSetState(-1, $GUI_DISABLE)
$lbDirectories = GUICtrlCreateList("", 104, 16, 506, 71)
$btMonitor = GUICtrlCreateButton("Start Monitor", 632, 24, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Monitor")
GUICtrlSetState(-1, $GUI_DISABLE)
$btClear = GUICtrlCreateButton("Clear", 632, 56, 75, 25, 0)
GUICtrlSetOnEvent(-1, "_OnEvent_Clear")
GUICtrlCreateGroup("", -99, -99, 1, 1)
$lvNotifications = GUICtrlCreateListView("Action|Time|File", 8, 112, 714, 262)
GUICtrlSendMsg(-1, 0x101E, 0, Int(.1 * 710))
GUICtrlSendMsg(-1, 0x101E, 1, Int(.2 * 710))
GUICtrlSendMsg(-1, 0x101E, 2, Int(.7 * 710) - 20)
GUISetState(@SW_SHOW)

While 1
    If Not $bMonitoring And _GUICtrlListBox_GetCurSel($lbDirectories) <> -1 And GUICtrlGetState($btRemove) = $GUI_SHOW + $GUI_DISABLE Then
        GUICtrlSetState($btRemove, $GUI_ENABLE)
    EndIf
    Sleep(20)
WEnd

Func _ReportChanges($Action, $FilePath)
    Local $hTime
    $hTime = _Date_Time_GetSystemTime()
    _GUICtrlListView_InsertItem($lvNotifications, $Action, 0)
    _GUICtrlListView_AddSubItem($lvNotifications, 0, _Date_Time_SystemTimeToDateTimeStr($hTime), 1)
    _GUICtrlListView_AddSubItem($lvNotifications, 0, $FilePath, 2)
EndFunc   ;==>_ReportChanges

Func _OnEvent_Add()
    Local $sDir, $nMax, $i
    $sDir = FileSelectFolder("Select directory to monitor", "")
    If $sDir <> "" Then
        If StringRight($sDir, 1) <> "" Then $sDir &= ""
        $nMax = _GUICtrlListBox_GetCount($lbDirectories) - 1
        For $i = 0 To $nMax
            If _GUICtrlListBox_GetText($lbDirectories, $i) = $sDir Then Return
        Next
        _GUICtrlListBox_AddString($lbDirectories, $sDir)

        GUICtrlSetState($btMonitor, $GUI_ENABLE)

    EndIf
EndFunc   ;==>_OnEvent_Add

Func _OnEvent_Clear()
    _GUICtrlListView_DeleteAllItems(GUICtrlGetHandle($lvNotifications))
EndFunc   ;==>_OnEvent_Clear

Func _OnEvent_Close()
    If $bMonitoring Then _MonitorDirectory()
    Exit
EndFunc   ;==>_OnEvent_Close

Func _OnEvent_Monitor()
    If Not $bMonitoring Then
        $bMonitoring = True
        GUICtrlSetData($btMonitor, "Stop Monitor")
        GUICtrlSetState($btAdd, $GUI_DISABLE)
        GUICtrlSetState($btRemove, $GUI_DISABLE)
        GUICtrlSetState($lbDirectories, $GUI_DISABLE)
        $n = _GUICtrlListBox_GetCount($lbDirectories)
        Local $Dirs[$n]
        For $i = 0 To $n - 1
            $Dirs[$i] = _GUICtrlListBox_GetText($lbDirectories, $i)
        Next
        _MonitorDirectory($Dirs)
    Else
        $bMonitoring = False
        GUICtrlSetState($lbDirectories, $GUI_ENABLE)
        GUICtrlSetState($btAdd, $GUI_ENABLE)
        GUICtrlSetData($btMonitor, "Start Monitor")
        _MonitorDirectory()
    EndIf
EndFunc   ;==>_OnEvent_Monitor

Func _OnEvent_Remove()
    _GUICtrlListBox_DeleteString($lbDirectories, _GUICtrlListBox_GetCurSel($lbDirectories))
    If _GUICtrlListBox_GetCount($lbDirectories) = 0 Then
        GUICtrlSetState($btMonitor, $GUI_DISABLE)
    EndIf
EndFunc   ;==>_OnEvent_Remove



;~ =========================== FUNCTION _MonitorDirectory() ==============================
#cs
    Description:     Monitors the user defined directories for file activity.
    Original:        http://www.autoitscript.com/forum/index.php?showtopic=69044&hl=folderspy&st=0
    Modified:        Jack Chen
    Syntax:         _MonitorDirectory($Dirs = "", $Subtree = True, $TimerMs = 250, $Function = "_ReportChanges")
    Parameters:
                    $Dirs          - Optional: Zero-based array of valid directories to be monitored.
                    $Subtree       - Optional: Subtrees will be monitored if $Subtree = True.
                    $TimerMs       - Optional: Timer to register changes in milliseconds.
                    $Function      - Optional: Function to launch when changes are registered. e.g. _ReportChanges
                    Syntax of your function must be e.g._ReportChanges($Action, $FilePath)
                    Possible actions: Created, Deleted, Modified, Rename-, Rename+, Unknown
    Remarks:        Call _MonitorDirectory() without parameters to stop monitoring all directories.
                    THIS SHOULD BE DONE BEFORE EXITING SCRIPT AT LEAST.
#ce

Func _MonitorDirectory($Dirs = "", $Subtree = True, $TimerMs = 250, $Function = "_ReportChanges")
    Local Static $nMax, $hBuffer, $hEvents, $aSubtree, $sFunction
    If IsArray($Dirs) Then
        $nMax = UBound($Dirs)
    ElseIf $nMax < 1 Then
        Return
    EndIf
    Local Static $aDirHandles[$nMax], $aOverlapped[$nMax], $aDirs[$nMax]
    If IsArray($Dirs) Then
        $aDirs = $Dirs
        $aSubtree = $Subtree
        $sFunction = $Function
;~      $hBuffer = DllStructCreate("byte[4096]")
        $hBuffer = DllStructCreate("byte[65536]")
        For $i = 0 To $nMax - 1
            If StringRight($aDirs[$i], 1) <> "" Then $aDirs[$i] &= ""
;~  http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx
            $aResult = DllCall("kernel32.dll", "hwnd", "CreateFile", "Str", $aDirs[$i], "Int", 0x1, "Int", BitOR(0x1, 0x4, 0x2), "ptr", 0, "int", 0x3, "int", BitOR(0x2000000, 0x40000000), "int", 0)
            $aDirHandles[$i] = $aResult[0]
            $aOverlapped[$i] = DllStructCreate("ulong_ptr Internal;ulong_ptr InternalHigh;dword Offset;dword OffsetHigh;handle hEvent")
            For $j = 1 To 5
                DllStructSetData($aOverlapped, $j, 0)
            Next
            _SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i], True, $aSubtree)
        Next
        $hEvents = DllStructCreate("hwnd hEvent[" & UBound($aOverlapped) & "]")
        For $j = 1 To UBound($aOverlapped)
            DllStructSetData($hEvents, "hEvent", DllStructGetData($aOverlapped[$j - 1], "hEvent"), $j)
        Next
        AdlibRegister("_GetChanges", $TimerMs)
    ElseIf $Dirs = "ReadDirChanges" Then
        _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs, $aSubtree, $sFunction)
    ElseIf $Dirs = "" Then
        AdlibUnRegister("_GetChanges")
;~  Close Handle
        For $i = 0 To $nMax - 1
            DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $aDirHandles[$i])
            DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $aOverlapped[$i])
        Next
        DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hEvents)
        $nMax = 0
        $hBuffer = ""
        $hEvents = ""
        $aDirHandles = ""
        $aOverlapped = ""
        $aDirs = ""
        $aSubtree = ""
        $sFunction = ""
    EndIf
EndFunc   ;==>_MonitorDirectory

Func _SetReadDirectory($hDir, $hBuffer, $hOverlapped, $bInitial, $bSubtree)
    Local $hEvent, $pBuffer, $nBufferLength, $pOverlapped
    $pBuffer = DllStructGetPtr($hBuffer)
    $nBufferLength = DllStructGetSize($hBuffer)
    $pOverlapped = DllStructGetPtr($hOverlapped)
    If $bInitial Then
        $hEvent = DllCall("kernel32.dll", "hwnd", "CreateEvent", "UInt", 0, "Int", True, "Int", False, "UInt", 0)
        DllStructSetData($hOverlapped, "hEvent", $hEvent[0])
    EndIf
;~  http://msdn.microsoft.com/en-us/library/aa365465%28VS.85%29.aspx
    $aResult = DllCall("kernel32.dll", "Int", "ReadDirectoryChangesW", "hwnd", $hDir, "ptr", $pBuffer, "dword", $nBufferLength, "int", $bSubtree, "dword", BitOR(0x1, 0x2, 0x4, 0x8, 0x10, 0x40, 0x100), "Uint", 0, "Uint", $pOverlapped, "Uint", 0)
    Return $aResult[0]
EndFunc   ;==>_SetReadDirectory

Func _GetChanges()
    _MonitorDirectory("ReadDirChanges")
EndFunc   ;==>_GetChanges

Func _GetDirectoryChanges($aDirHandles, $hBuffer, $aOverlapped, $hEvents, $aDirs, $aSubtree, $sFunction)
    Local $aMsg, $i, $nBytes = 0
    $aMsg = DllCall("User32.dll", "dword", "MsgWaitForMultipleObjectsEx", "dword", UBound($aOverlapped), "ptr", DllStructGetPtr($hEvents), "dword", -1, "dword", 0x4FF, "dword", 0x6)
    $i = $aMsg[0]
    Switch $i
        Case 0 To UBound($aDirHandles) - 1
            DllCall("Kernel32.dll", "Uint", "ResetEvent", "uint", DllStructGetData($aOverlapped[$i], "hEvent"))
            _ParseFileMessages($hBuffer, $aDirs[$i], $sFunction)
            _SetReadDirectory($aDirHandles[$i], $hBuffer, $aOverlapped[$i], False, $aSubtree)
            Return $nBytes
    EndSwitch
    Return 0
EndFunc   ;==>_GetDirectoryChanges

Func _ParseFileMessages($hBuffer, $sDir, $sFunction)
    Local $hFileNameInfo, $pBuffer, $FilePath
    Local $nFileNameInfoOffset = 12, $nOffset = 0, $nNext = 1
    $pBuffer = DllStructGetPtr($hBuffer)
    While $nNext <> 0
        $hFileNameInfo = DllStructCreate("dword NextEntryOffset;dword Action;dword FileNameLength", $pBuffer + $nOffset)
        $hFileName = DllStructCreate("wchar FileName[" & DllStructGetData($hFileNameInfo, "FileNameLength") / 2 & "]", $pBuffer + $nOffset + $nFileNameInfoOffset)
        Switch DllStructGetData($hFileNameInfo, "Action")
            Case 0x1 ; $FILE_ACTION_ADDED
                $Action = "Created"
            Case 0x2 ; $FILE_ACTION_REMOVED
                $Action = "Deleted"
            Case 0x3 ; $FILE_ACTION_MODIFIED
                $Action = "Modified"
            Case 0x4 ; $FILE_ACTION_RENAMED_OLD_NAME
                $Action = "Rename-"
            Case 0x5 ; $FILE_ACTION_RENAMED_NEW_NAME
                $Action = "Rename+"
            Case Else
                $Action = "Unknown"
        EndSwitch

        $FilePath = $sDir & DllStructGetData($hFileName, "FileName")
        Call($sFunction, $Action, $FilePath) ; Launch the specified function
        $nNext = DllStructGetData($hFileNameInfo, "NextEntryOffset")
        $nOffset += $nNext
    WEnd
EndFunc   ;==>_ParseFileMessages
;~ ===========================End of FUNCTION _MonitorDirectory() ==============================
发表于 2013-2-7 11:09:20 | 显示全部楼层
好长的代码啊
发表于 2013-2-8 07:59:38 | 显示全部楼层
试试读取文件如果不让读就是没写完
 楼主| 发表于 2013-2-13 19:33:48 | 显示全部楼层
我现在用了_WinAPI_FileInUse函数判断文件是否在使用,如果使用就sleep500
                 While _WinAPI_FileInUse($FilePath) =1
                        sleep(500)
                        _FileWriteLog(@ScriptDir & "\Filelog.log","文件正在使用中>>Sleep500")
                 Wend
但是我发现这个函数也不是百分之百准确,当我从网络复制文件时,发现有时明明正在复制文件,可是函数却反回了0..不知哪位大侠有什么更好的办法呀?
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-11-16 01:49 , Processed in 0.078555 second(s), 24 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表