C#守护进程用于读取大量文件

时间:2016-03-23 13:33:54

标签: c# multithreading file filesystemwatcher

我将首先介绍一些背景

简介

我正在创建一个将在服务器上连续运行的程序。该计划的一部分是能够向不同的代表发送自动邮件。这些邮件的内容将自动放入一个文件夹中,因此当新内容准备好并且读取此文件中的文本时,需要通知程序。然而,这不是问题,我已经有了解决方案。

问题

可能会同时在文件夹中放置多个文件,这时我的程序无法处理它。我得到以下异常:

  

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方法中,我尝试了以下

  1. File.ReadAllText(filePath) 我认为这是阅读文件的标准方式,但这不起作用
  2. using (StreamReader sr = new StreamReader(filePath)){ String line = sr.ReadToEnd();} 来自microsoft
  3. 我已经尝试Thread.Sleep(5000)看看它是否需要一些时间,没有效果
  4. 每次我开始阅读时,我都尝试使用进入readlock的ReaderWriterLockSlim类,此解决方案有时可行,但不足以保证
  5. 我已经尝试将每个文件放在一个列表中,然后迭代该列表但仍然给我相同的异常
  6. 问题

    有没有办法处理多个文件同时放入文件夹的事件?

2 个答案:

答案 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.
            }
        }
    }
}