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

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

我猜可能是因为该文件不可用于导入。

stream.saveToFile之后的代码是否asynchronous运行或等待,直到文件保存到目的地? 是否有callback来检查,如果该文件实际上保存?

代码片段:

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 

ADODB Stream SaveToFile方法在这里由MSDNlogging – 没有提及它是同步的还是asynchronous的,所以我猜测它实际上是同步的,并在进程完成并释放文件句柄时返回。

除了我已经学会了不要相信这个关于文件写入的假设:即使是本地写入磁盘,也不会在networking上写入:现代文件系统太“聪明”,并且存在太多的caching和中间逻辑。

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

  1. 它存在;
  2. 它有一个非零的长度;
  3. 自从你上次检查date戳以来没有改变。

我的推荐:

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

一个快速和脏的方法是检测一个零文件的大小,因为这是通过查询文件系统返回一个文件仍然被写入的结果:

 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是我在Excel中select的“暂停”声明 – 我更喜欢睡觉 – 但是您可能有自己的工具:确保您不会阻塞文件写入线程!

我怀疑你的bas文件会大到足以显示大小的增加,直到完成,所以零或完成的testing可能是足够好的。 为了完整性,下面是我用于较大对象的代码:

 ' 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

请注意,我没有使用文件长度检查 – 是的,我知道你可以看到它在一个非常长的操作文件资源pipe理器中增加,你可以检查stream交付的最终位数 – 但“停止生长“而且”和我预期的一样大“并不像”文件系统最近没有人写过的文件系统“那样可靠 – 而那些关于”最近“和持久性文件locking的假设是最愚蠢的假设在桌子上。

是的,“最愚蠢的”是如此之好。 有一天,我会写一个'Falsehoods开发人员相信…'文件的文件:但麻烦不是编码人员的错误观念,它的误导和不一致的文件系统行为。

另外请注意,我没有为我的文件操作使用Scripting.FileSystemObject类:我没有任何文档列出它们的File对象的caching和缓冲行为,我不太相信它给我一个直接的“快照”文件状态。 VBA.FileSystem是令人安心的愚蠢的,你可以得到更多的信息错误 – 如此多,以至于如果在写入过程中文件被locking的特别繁重,你可能需要插入一个On Error Resume Next

后记:

当然,您可以尝试一个文件“移动”命令作为最终检查:但是,当您尝试将.bas文件导入到您的项目中时,通过面朝前走入文件锁,您不会发现任何内容。 如果你的问题是导入部分写入的文件,没有错误和文件锁的警告,那么我会实际上走下去计算位数,检查文件大小和移动文件到“分段”文件夹的路线。 值得指出的是,文件locking错误是一个保护,也是一个烦恼!