文件可访问时是否可能引发事件?
在CI中,可以使用FileSystemWatcher对象监视特定文件,并在创建,修改等事件时引发事件。
我使用此类的问题是,即使创建文件的过程仍在编写过程中,它也会在创建文件时引发事件。我发现这很成问题,尤其是当我尝试读取XML文档之类的文件时,该文件必须具有某种结构,直到完成写入,该结构才存在。
在文件可访问之后,.NET(最好是2.0)是否有任何引发事件的方法,还是我必须不断尝试读取文件,直到它不会抛出异常才知道它是可用的?
解决方案
回答
不知道标准班级是否真的有办法引发事件,但是我在最近所做的一些工作中遇到了类似的问题。
简而言之,我试图写入当时被锁定的文件。我结束了对write方法的包装,因此它将在几毫秒后自动尝试再次进行写操作。
大声思考,我们可以探测该文件的只读状态吗?那么可能值得拥有一个文件IO的包装器,该包装器可以将委托进行堆栈以进行未决的文件操作或者其他操作。
回答
在带有OPEN_EXISTING标志和FILE_ALL_ACCESS的循环中使用CreateFile(或者我们可能只需要一个子集,请参阅http://msdn.microsoft.com/zh-cn/library/aa364399(VS.85).aspx
检查针对-1(INVALID_ HANDLE_ VALUE)返回的句柄是否失败。它仍在轮询,但这将节省抛出异常的成本。
编辑:此编辑器/标记不能处理下划线!呸!
回答
我们可以使用文件系统监视程序来检查何时更改了文件。仅在先前具有该文件的任何程序关闭该文件之后,它才会"更改"。我知道我们要求使用C#,但是我的VB.Net更好。希望我们或者其他人可以翻译。
它尝试打开文件(如果不可用),它添加一个观察程序,并等待文件被更改。更改文件后,它将尝试再次打开。如果等待时间超过120秒,它将引发异常,因为我们可能会陷入永不释放文件的情况。另外,我决定添加一个等待5秒的文件更改超时,以防在创建实际文件监视程序之前关闭文件的可能性很小。
Public Sub WriteToFile(ByVal FilePath As String, ByVal FileName As String, ByVal Data() As Byte) Dim FileOpen As Boolean Dim File As System.IO.FileStream = Nothing Dim StartTime As DateTime Dim MaxWaitSeconds As Integer = 120 StartTime = DateTime.Now FileOpen = False Do Try File = New System.IO.FileStream(FilePath & FileName, IO.FileMode.Append) FileOpen = True Catch ex As Exception If DateTime.Now.Subtract(StartTime).TotalSeconds > MaxWaitSeconds Then Throw New Exception("Waited more than " & MaxWaitSeconds & " To Open File.") Else Dim FileWatch As System.IO.FileSystemWatcher FileWatch = New System.IO.FileSystemWatcher(FilePath, FileName) FileWatch.WaitForChanged(IO.WatcherChangeTypes.Changed,5000) End If FileOpen = False End Try Loop While Not FileOpen If FileOpen Then File.Write(Data, 0, Data.Length) File.Close() End If End Sub
回答
Kibbe的答案似乎正确,但对我没有用。看来FileSystemWatcher有一个错误。所以我写了我自己的WaitForChanged:
using (var watcher = new FileSystemWatcher(MatlabPath, fileName)) { var wait = new EventWaitHandle(false, EventResetMode.AutoReset); watcher.EnableRaisingEvents = true; watcher.Changed += delegate(object sender, FileSystemEventArgs e) { wait.Set(); }; if (!wait.WaitOne(MillissecondsTimeout)) { throw new TimeoutException(); } }