【问题标题】:How can I determine if a file is locked using VBS?如何确定文件是否使用 VBS 锁定?
【发布时间】:2012-08-31 07:24:26
【问题描述】:

我正在编写一个 VB 脚本来更新网络上的一些文件。在开始之前,我想知道是否有任何文件被锁定。我想我实际上做任何更新之前这样做。

我知道如果在尝试替换文件时文件被锁定,我可以处理该错误,但我真的想知道在开始更新任何文件之前是否有任何文件被锁定。

有什么方法可以查看使用 VBS 锁定的文件(除了尝试替换它)?

【问题讨论】:

    标签: vbscript wsh filesystemobject


    【解决方案1】:

    或者,更简单地说:

    假设您的 VBS 中已经有一个名为 FileName 的变量,其中包含您要测试的完整文件路径:

    Dim oFso, oFile
    Set oFso = CreateObject("Scripting.FileSystemObject")
    Set oFile = oFso.OpenTextFile(FileName, 8, True)
    If Err.Number = 0 Then oFile.Close
    

    第 3 行尝试在启用附加权限的情况下打开您要测试的文件。例如它尝试使用写锁打开文件。

    如果使用写锁打开文件会产生错误,那么您的 VBS 将在第三行出错并且无法继续。此时,您应该从调用 VBS 的任何位置进行错误处理。如果您无法获得写锁定,则错误消息将是“Permission Denied”。

    如果使用锁打开文件不会导致错误,则第 4 行再次将其关闭。您现在可以打开文件或对它做任何您想做的事情,确信它没有写锁。

    【讨论】:

      【解决方案2】:

      此函数确定是否可以在“写入”模式下访问感兴趣的文件。这与确定文件是否被进程锁定并不完全相同。不过,您可能会发现它适用于您的情况。 (至少在出现更好的东西之前。)

      当文件被另一个进程锁定时,此函数将指示无法进行“写”访问。但是,它无法将该条件与其他阻止“写”访问的条件区分开来。例如,如果文件设置了只读位或拥有限制性 NTFS 权限,则也无法进行“写入”访问。当进行“写入”访问尝试时,所有这些情况都会导致“权限被拒绝”。

      还要注意,如果一个文件被另一个进程锁定了,这个函数返回的答案只有在函数执行的那一刻才是可靠的。所以,并发问题是可能的。

      如果找到以下任一条件,则会引发异常:“找不到文件”、“找不到路径”或“非法文件名”(“错误的文件名或编号”)。

      Function IsWriteAccessible(sFilePath)
          ' Strategy: Attempt to open the specified file in 'append' mode.
          ' Does not appear to change the 'modified' date on the file.
          ' Works with binary files as well as text files.
      
          ' Only 'ForAppending' is needed here. Define these constants
          ' outside of this function if you need them elsewhere in
          ' your source file.
          Const ForReading = 1, ForWriting = 2, ForAppending = 8
      
          IsWriteAccessible = False
      
          Dim oFso : Set oFso = CreateObject("Scripting.FileSystemObject")
      
          On Error Resume Next
      
          Dim nErr : nErr = 0
          Dim sDesc : sDesc = ""
          Dim oFile : Set oFile = oFso.OpenTextFile(sFilePath, ForAppending)
          If Err.Number = 0 Then
              oFile.Close
              If Err Then
                  nErr = Err.Number
                  sDesc = Err.Description
              Else
                  IsWriteAccessible = True
              End if
          Else
              Select Case Err.Number
                  Case 70
                      ' Permission denied because:
                      ' - file is open by another process
                      ' - read-only bit is set on file, *or*
                      ' - NTFS Access Control List settings (ACLs) on file
                      '   prevents access
      
                  Case Else
                      ' 52 - Bad file name or number
                      ' 53 - File not found
                      ' 76 - Path not found
      
                      nErr = Err.Number
                      sDesc = Err.Description
              End Select
          End If
      
          ' The following two statements are superfluous. The VB6 garbage
          ' collector will free 'oFile' and 'oFso' when this function completes
          ' and they go out of scope. See Eric Lippert's article for more:
          '   http://blogs.msdn.com/b/ericlippert/archive/2004/04/28/when-are-you-required-to-set-objects-to-nothing.aspx
      
          'Set oFile = Nothing
          'Set oFso = Nothing
      
          On Error GoTo 0
      
          If nErr Then
              Err.Raise nErr, , sDesc
          End If
      End Function
      

      【讨论】:

      • Darin 指出(在其他答案中)该模块应包括:Const ForReading = 1, ForWriting = 2, ForAppending = 8
      • @Smandoli - 感谢您提醒我注意这个遗漏。我已经相应地更新了代码。还要注意我在函数末尾将oFileoFso 设置为Nothing 之前的评论。
      【解决方案3】:

      下面的脚本尝试写入文件 30 秒,然后放弃。当我们所有的用户都必须点击一个脚本时,我需要这个。可能有多个用户尝试同时写入。 OpenCSV() 尝试打开文件 30 次,中间有 1 秒的延迟。

        Const ForAppending = 8
      
        currentDate = Year(Now) & "-" & Month(Now) & "-" & Day(Now) & " " & Hour(Now) & ":" & Minute(Now) & ":" & Second(Now)
        filepath = "\\network\path\file.csv"
        Set oCSV = OpenCSV( filepath ) 
        oCSV.WriteLine( currentDate )
        oCSV.Close
      
        Function OpenCSV( path )
          Set oFS = CreateObject( "Scripting.FileSystemObject" )
          For i = 0 To 30
            On Error Resume Next
            Set oFile = oFS.OpenTextFile( path, ForAppending, True )
            If Not Err.Number = 70 Then
              Set OpenCSV = oFile
              Exit For
            End If
            On Error Goto 0
            Wscript.Sleep 1000
          Next
          Set oFS = Nothing
          Set oFile = Nothing
          If Err.Number = 70 Then
            MsgBox "File " & filepath & " is locked and timeout was exceeded.", vbCritical
            WScript.Quit
          End If
        End Function
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-25
        • 1970-01-01
        • 2014-03-16
        相关资源
        最近更新 更多