Tai*_*red 38 c# filesystemwatcher exception-handling file-access
当多个文件放入监视目录时,我遇到了FileSystemWatcher的问题.我想在文件放入目录后立即解析它.通常,第一个文件解析正常,但向目录添加第二个文件会导致访问问题.偶尔,第一个文件甚至不会解析.只有一个应用程序正在运行并正在查看此目录.最终,此进程将在多台计算机上运行,并且它们将监视共享目录,但只有一台服务器可以解析每个文件,因为数据已导入数据库且没有主键.
这是FileSystemWatcher代码:
public void Run() {
FileSystemWatcher watcher = new FileSystemWatcher("C:\\temp");
watcher.NotifyFilter = NotifyFilters.FileName;
watcher.Filter = "*.txt";
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
}
Run Code Online (Sandbox Code Playgroud)
然后是解析文件的方法:
private void OnChanged(object source, FileSystemEventArgs e) {
string line = null;
try {
using (FileStream fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.None)) {
using (StreamReader sr = new StreamReader(fs)) {
while (sr.EndOfStream == false) {
line = sr.ReadLine();
//parse the line and insert into the database
}
}
}
}
catch (IOException ioe) {
Console.WriteLine("OnChanged: Caught Exception reading file [{0}]", ioe.ToString());
}
Run Code Online (Sandbox Code Playgroud)
移动第二个文件时,它正在捕捉
System.IO.IOException:进程无法访问文件'C:\ Temp\TestFile.txt',因为它正由另一个进程使用.
如果它在多台机器上运行,我希望看到这个错误,但它现在只在一台服务器上运行.不应该有另一个使用此文件的进程 - 我创建它们并在应用程序运行时将它们复制到目录中.
这是设置FileSystemWatcher的正确方法吗?如何查看此文件的锁定?为什么不解析这两个文件 - 我是否必须关闭FileStream?我想保留FileShare.None选项,因为我只想要一个服务器来解析文件 - 获取文件的服务器首先解析它.
Dir*_*mar 52
此方法的典型问题是在触发事件时仍在复制文件.显然,您将获得异常,因为文件在复制期间被锁定.大文件特别容易出现异常.
作为一种解决方法,您可以先复制该文件,然后重命名该文件并收听重命名事件.
或者另一种选择是使用while循环检查是否可以使用写访问权打开文件.如果可以,您将知道复制已完成.C#代码可能如下所示(在生产系统中,您可能希望具有最大重试次数或超时而不是a while(true)):
/// <summary>
/// Waits until a file can be opened with write permission
/// </summary>
public static void WaitReady(string fileName)
{
while (true)
{
try
{
using (Stream stream = System.IO.File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (stream != null)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} ready.", fileName));
break;
}
}
}
catch (FileNotFoundException ex)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
}
catch (IOException ex)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
}
catch (UnauthorizedAccessException ex)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
}
Thread.Sleep(500);
}
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是在复制完成后在文件夹中放置一个小的触发器文件.您的FileSystemWatcher只会侦听触发器文件.
G-M*_*Mac 10
我上面已经发表评论,但我还没有足够的分数.
对这个问题的评价最高的答案有一段看起来像这样的代码:
using (Stream stream = System.IO.File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (stream != null)
{
System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} ready.", fileName));
break;
}
}
Run Code Online (Sandbox Code Playgroud)
使用FileShare.ReadWrite设置的问题在于它正在请求访问该文件,主要是说"我想读/写这个文件,但其他人也可以读/写它".这种方法在我们的情况下失败了 接收远程传输的进程没有锁定文件,但它正在积极地写入它.我们的下游代码(SharpZipLib)因"正在使用文件"异常而失败,因为它试图打开文件FileShare.Read("我想要读取文件,只允许其他进程读取").由于打开文件的进程已经写入,因此该请求失败.
但是,上面的响应中的代码太宽松了.通过使用FileShare.ReadWrite,它成功获得了对文件的访问权限(因为它要求可以兑现的共享限制),但下游调用仍然失败.
调用中的共享设置File.Open应为FileShare.Read或FileShare.None,而不是 FileShare.ReadWrite.
| 归档时间: |
|
| 查看次数: |
38023 次 |
| 最近记录: |