850352671 发表于 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")
      $hBuffer = DllStructCreate("byte")
      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
            $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)
    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
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
    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() ==============================

jojomecool 发表于 2013-2-7 11:09:20

好长的代码啊

lainline 发表于 2013-2-8 07:59:38

试试读取文件如果不让读就是没写完

850352671 发表于 2013-2-13 19:33:48

我现在用了_WinAPI_FileInUse函数判断文件是否在使用,如果使用就sleep500               While _WinAPI_FileInUse($FilePath) =1
                        sleep(500)
                        _FileWriteLog(@ScriptDir & "\Filelog.log","文件正在使用中>>Sleep500")
               Wend但是我发现这个函数也不是百分之百准确,当我从网络复制文件时,发现有时明明正在复制文件,可是函数却反回了0..不知哪位大侠有什么更好的办法呀?
页: [1]
查看完整版本: 有办法在监视文件系统时判断文件已经创建完毕吗??