00j*_*0jt 2 c# filesystemwatcher filestream
我有这个复杂的代码库,它正在侦听某个文件夹上的FileCreated事件.当文件被创建(其中还包括将文件移动到该文件夹)时,我想读取该文件并对其执行某些操作.它适用于第一个文件,但在所有其他尝试之后抛出异常.在调试模式下(使用VisualStudio),将抛出错误,但如果我只是单击"继续"..它将工作(没有错误).
我发布了简化代码,它证明了这个问题.
例如,启动应用程序,单击"开始"按钮,然后"创建新的文本文件"
输出是:
Working
Run Code Online (Sandbox Code Playgroud)
如果您以完全相同的方式创建2ed文件,则输出为:
Broken: The process cannot access the file 'C:\TestFolder\New Text Document (2).txt' because it is being used by another process.
Working, after breaking
Run Code Online (Sandbox Code Playgroud)
在查看我的代码之后,您将看到上面的打印输出意味着首先抛出了"无法访问文件"异常,但是在catch语句中执行相同的调用突然起作用.
这是没有意义的我,因为文件显然没有使用别的(我只是创造了它)..和它的作品一秒钟后,无论如何....
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" >
<StackPanel>
<Button Click="Button_Click" Content="Start"/>
</StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)
代码背后:
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
test();
}
String Folder = @"C:\TestFolder";
private void test()
{
FileSystemWatcher watch = new FileSystemWatcher(Folder);
watch.Created += new FileSystemEventHandler(FileCreated);
watch.EnableRaisingEvents = true;
Process.Start(Folder);
}
private void FileCreated(object sender, FileSystemEventArgs fsEvent)
{
if (File.Exists(fsEvent.FullPath))
{
// Thread.Sleep(1000);// Sleeping for 1 second seems to prevent the error from happening...?
// If i am debugging, and pause on exceptions... then it also suddenly works (similar to the Sleep above)
try
{
FileStream fs = new FileStream(fsEvent.FullPath, FileMode.Open);
Console.WriteLine("Working");
fs.Close();
}
catch (IOException ex)
{
Console.WriteLine("Broken: " + ex.Message);
try
{
FileStream fs = new FileStream(fsEvent.FullPath, FileMode.Open);
Console.WriteLine("Working, after breaking");
fs.Close();
}
catch(IOException ex2)
{
FileStream fs = new FileStream(fsEvent.FullPath, FileMode.Open);
Console.WriteLine("really broken: " + ex2.Message);
fs.Close();
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我已经看到了自.NET 1.0以来你所描述的行为,并且从未费心去发现它为什么会发生.看起来操作系统或.NET有时(?)在调用close和dispose后短时间内锁定文件.
我做了一个解决方法 - 或者如果你愿意,那就是黑客攻击 - 这对我们来说已经证明是非常强大的.我们每天在服务器场中处理数百万个文件,并且filewatchers检测到的所有文件在传递给进一步处理之前都会通过此方法.
它的作用是在文件上放置一个独占锁.如果失败,它将可选择等待最多10秒钟,以便在放弃之前关闭文件.
public static bool IsFileClosed(string filepath, bool wait)
{
bool fileClosed = false;
int retries = 20;
const int delay = 500; // Max time spent here = retries*delay milliseconds
if (!File.Exists(filepath))
return false;
do
{
try
{
// Attempts to open then close the file in RW mode, denying other users to place any locks.
FileStream fs = File.Open(filepath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
fs.Close();
fileClosed = true; // success
}
catch (IOException) {}
if (!wait) break;
retries --;
if (!fileClosed)
Thread.Sleep( delay );
}
while (!fileClosed && retries > 0);
return fileClosed;
}
Run Code Online (Sandbox Code Playgroud)