我有 .NET 3.5 ClickOnce 应用程序。有一个简单的网格,其中包含存储在服务器上的 Word 文档列表。单击按钮时,应用程序从服务器(通过 WCF)下载选定的文档并将其放入定义的临时文件夹中。之后,使用以下函数计算文档的哈希:
Public Shared Function HashFile(ByVal file As String) As String
Using reader As New System.IO.FileStream(file, IO.FileMode.Open, IO.FileAccess.Read)
Using provider As New System.Security.Cryptography.MD5CryptoServiceProvider
Dim hash() As Byte = provider.ComputeHash(reader)
Dim sb As New System.Text.StringBuilder(hash.Length * 2)
For i As Integer = 0 To hash.Length - 1
sb.Append(hash(i).ToString("X2"))
Next
Return sb.ToString().ToLower
End Using
End Using
End Function
然后打开Word文档:
Private Shared Function OpenDocument(ByVal path As String) As Boolean
Try
Dim process As New Process
process.StartInfo.FileName = path
process.StartInfo.UseShellExecute = True
process.StartInfo.ErrorDialog = True
process.Start()
Return True
Catch ex As Exception
Return False
End Try
End Function
应用程序中有所有打开的文档的列表。打开文档后,有关它的信息将立即添加到此列表中。到目前为止,非常简单。应用程序中有一个计时器,每 1000 毫秒计时一次,并检查是否已经关闭了任何打开的文档。因为没有简单的方法可以从 Word 中获取此类信息,所以使用了以下技巧:
Public Shared Function IsLockedFile(ByVal path As String) As Boolean
Dim isLocked As Boolean = True
Try
Using fs As FileStream = File.Open(path, FileMode.Open, FileAccess.Write)
isLocked = False
End Using
Catch ex As Exception
End Try
Return isLocked
End Function
如果应用程序成功打开具有写访问权限的文件,则意味着该文档已关闭(不再被 Word 锁定)。之后,使用与上述相同的函数再次计算文件的 MD5 哈希值。如果旧哈希值等于新哈希值,则表示用户没有对文档进行任何更改。如果哈希值不同,则将文档上传到服务器。那是对整个过程的简化描述。
它工作得很好。但是,客户报告有时会丢失对文档的更改。久而久之,终于找到了原因。当应用程序计算(关闭的)文档的哈希值时,它有时会返回旧的哈希值。就像它仍在读取文件的旧版本一样。错误的发生是非常不确定的。大多数情况下它工作正常。例如 50 次我得到正确的(不同的)哈希,但连续 3 次是错误的(旧的)哈希。
我无法在我的开发人员环境(VMware 中虚拟化的 Windows Server 2008)中模拟该错误,只能在主机中(Windows 7 64 位,防病毒关闭)。
我什至尝试在重新计算哈希之前延迟一些时间,以确保刷新所有磁盘操作。但即使在 2 秒后我仍然错了,老哈希。也许这还不够,但我应该等多久?
从我用谷歌搜索的内容来看,只能刷新使用 .NET 应用程序进行的 IO 操作,而不是在它之外。读取哈希时的读/写独占打开也无济于事。任何想法如何解决这个问题或其他可能导致它的原因?
谢谢。