ADODB.Stream.saveToFile - >等到文件保存?

时间:2016-02-05 08:52:23

标签: excel vba excel-vba

我想知道ostream.saveToFile的行为。我从服务器下载vba模块,然后将其添加到当前工作簿onWorkbookOpen。但有时该模块不会添加到WorkbookOpen上的工作簿中。

我想原因可能是,该文件无法导入。

stream.saveToFile之后的代码是异步运行还是等待,直到文件保存到目标? 如果文件实际保存,是否有回调检查?

代码段:

 Dim WinHttpReq As Object
 Set WinHttpReq = CreateObject("WinHttp.WinHttpRequest.5.1")
 WinHttpReq.Option(4) = 13056 ' Ignore SSL Errors

 WinHttpReq.Open "GET", myURL, False     

 WinHttpReq.setRequestHeader "Accept", "*/*"
 WinHttpReq.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
 WinHttpReq.setRequestHeader "Proxy-Connection", "Keep-Alive"
 WinHttpReq.Send

 myURL = WinHttpReq.ResponseBody
 If WinHttpReq.Status = 200 Then
Set oStream = CreateObject("ADODB.Stream")
  oStream.Open
  oStream.Type = 1
  oStream.Write WinHttpReq.ResponseBody
  oStream.SaveToFile VBA.Environ("TEMP") & "\Module1.bas", 2
  oStream.Close

    If DoesComponentExist("Modul1") = True Then
    With ActiveWorkbook.VBProject
         .VBComponents.Remove .VBComponents("Modul1")
    End With
    End If
    If DoesComponentExist("Modul1") = False Then
         ThisWorkbook.VBProject.VBComponents.Import (VBA.Environ("TEMP") & "\Module1.bas")
    End If

  Else
        MsgBox "Returncode:" & WinHttpReq.Status & " Unable to download Code."
 End If

1 个答案:

答案 0 :(得分:2)

ADODB Stream SaveToFile method is documented here by MSDN - 没有提及它是同步还是异步,因此我猜测它实际上是同步的,并在进程完成并释放文件句柄时返回。 ..

...除了我已经学会了不相信有关文件写入的假设:甚至不是本地写入磁盘,而从不通过网络:现代文件系统也是如此&# 39;智能'并且有太多的缓存和中间逻辑。

这里的根本问题是我们没有任何可以告诉我们没有进程打开文件的内容。不要费心查找API调用:所有你得到的都是更复杂的错误,没有任何额外的保证。我们所能做的就是通过检查:

来推断他提供的文件
  1. 它存在;
  2. 长度非零;
  3. 自上次检查日期戳以来,它没有变化。
  4. 我的建议:

    使用VBA.FileSystem函数检查文件是否可用。

    快速而肮脏的方法是检测零文件大小,因为这是通过查询文件系统返回的文件仍返回的结果:< / p>

    
    Const MAX_WAIT As Integer = 10
    sFile = VBA.Environ("TEMP") & "\Module1.bas"
    ' Code to check a file exists: For i = 1 to MAX_WAIT If Len(VBA.FileSystem.Dir(sFile)) > 0 Then Exit For Application.Wait Now() + (i/3600/24) End If Next i
    If i >= MAX_WAIT Then ' Raise an error and exit End If

    ' Code to check a file has nonzero file size: For i = 1 to MAX_WAIT If VBA.FileSystem.FileLen(sFile) > 0 Then Exit For Application.Wait Now() + (i/3600/24) End If Next i
    If i >= MAX_WAIT Then ' Raise an error and exit End If

    Application.Wait是我的暂停&#39; Excel中的选择声明 - 我更喜欢睡眠 - 但你可能有自己的工具:确保你也没有阻止文件写入线程!

    我怀疑你的bas文件是否足够大以显示大小增加直到完成,因此零或完成的测试可能已经足够好了。为了完整起见,这里是我用于更大对象的代码:

    
    ' Code to check that file 'write' operations have stopped:
    For i = 1 to MAX_WAIT
        If VBA.FileSystem.FileDateTime(sFile) > (Now() + (2.5/3600/24)) Then
            Exit For
            Application.Wait Now() + (i/3600/24)
        End If
    Next i
    If i >= MAX_WAIT Then ' Raise an error. End If

    请注意,我没有使用文件长度检查 - 是的,我知道您可以在文件资源管理器中看到它在一个非常长的操作中增加,并且您可以检查流提供的最终位数 - 但是&#34;它已停止增长&#34; &#34;它的重量和我预期的一样大&#34; 不是&#39 ; t和&#34;文件系统说最近没有人写过&#34; - 以及最近&#39;和持久文件锁是表上最不愚蠢的假设。

    是的,&#39;最不愚蠢的&#39;尽可能好。有一天,我会为文件写a 'Falsehoods developers believe about...'文档:但问题不在于编码员之间的误解,而是文件系统中的误导和不一致的行为。

    另请注意,我没有使用Scripting.FileSystemObject类进行文件操作:我没有列出文件对象缓存和缓冲行为的文档,而且我没有&#39;相当信任它给我一个即时的快照&#39;文件状态。 VBA.FileSystem令人安心愚蠢,你可以从中获得更多信息性错误 - 如果文件在写入时以特别繁重的方式被锁定,则可能需要插入On Error Resume Next #39;正在进行中。

    后记:

    当然,你可以尝试一个文件&#39;移动&#39;命令作为最终检查:但是,当您尝试将.bas文件导入项目时,无论如何都不会告诉您通过首先进入文件锁定而无法发现。如果您的问题是导入部分写入的文件,没有错误和文件锁的警告,那么我实际上会沿着计算位数和检查文件大小以及将文件移动到“暂存”的路线走下去。夹。值得指出的是,文件锁定错误既是一种保护也是一种烦恼!