我有.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秒后我仍然出错,旧哈希。也许它没有用,但我还要等多久?
从我用Google搜索的内容来看,只有用.NET应用程序清除IO操作的可能性,而不是在它之外。读取哈希时读/写的独占开放也无济于事。任何想法如何解决这个或其他什么可能导致它?
感谢。