我将首先介绍一些背景
我正在创建一个将在服务器上连续运行的程序。该计划的一部分是能够向不同的代表发送自动邮件。这些邮件的内容将自动放入一个文件夹中,因此当新内容准备好并且读取此文件中的文本时,需要通知程序。然而,这不是问题,我已经有了解决方案。
可能会同时在文件夹中放置多个文件,这时我的程序无法处理它。我得到以下异常:
System.IO.IOException:进程无法访问文件 GENERATEDFILE ,因为它正由另一个进程使用。
一旦程序尝试读取已放入文件夹的文件,它就会给我这个例外,而我无法理解为什么会这样做
所以我有一个创建FileSystemWatcher的方法:
public void Watch(){
_watcher = new FileSystemWatcher();
_watcher.NotifyFilters = NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.FileName |
NotifyFilters.DirectoryName;
_watcher.Created += OnCreated
}
private void OnCreated(object sender, FileSystemEventArgs e){
//read the file that got created here and pass the content to an object that wille handle it further
}
非常简单,我们创建一个FileSystemWatcher,我们将一些NotifyFilters附加到它和OnCreated事件
在OnCreated方法中,我尝试了以下
File.ReadAllText(filePath)
我认为这是阅读文件的标准方式,但这不起作用using (StreamReader sr = new StreamReader(filePath)){
String line = sr.ReadToEnd();}
来自microsoft Thread.Sleep(5000)
看看它是否需要一些时间,没有效果ReaderWriterLockSlim
类,此解决方案有时可行,但不足以保证有没有办法处理多个文件同时放入文件夹的事件?
答案 0 :(得分:1)
如何捕获异常并将计时器设置为稍后重试?
答案 1 :(得分:1)
原因
文件创建事件在创建文件时发生,而不是在写完文件时发生。
解决方案
考虑为处理逻辑添加任务
创建文件时,文件名/路径将传递给在不断重试的任务中运行的方法。
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTestProject1
{
[TestClass]
public class UnitTest1
{
private ConcurrentQueue<string> _filesProcessQueue;
private FileSystemWatcher _watcher;
[TestMethod]
public void Watch()
{
_filesProcessQueue = new ConcurrentQueue<string>();
_watcher = new FileSystemWatcher
{
NotifyFilter = NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.FileName |
NotifyFilters.DirectoryName
};
_watcher.Created += OnCreated;
}
private void OnCreated(object sender, FileSystemEventArgs e)
{
// Create a task for reading the file after the lock is released
Task.Run(() => ProcessFileQueue(e.FullPath));
}
private void ProcessFileQueue(string fullPath)
{
bool processSuccess = false;
// TODO put terminator logic in here to stop retrying forever
while (processSuccess == false)
{
// TODO try process the file and return success/fail
processSuccess = true; // Continue to next file
//processSuccess = false; // Retry the same file
Task.Delay(TimeSpan.FromSeconds(5)); // Delay 5 seconds before retrying the file.
}
}
}
}