日期:2014-05-18  浏览次数:21288 次

FileSystemWatcher对象Created事件处理问题
各位大侠:
  我想做一个文件监控程序,当监控文件夹下有新的txt文件产生时,对文件进行读写操作,完成数据读取和相关计算后把该文件转存到其它目录,原文件删除。
  我自己写的created事件 是先获取监控文件下的所有文件,然后对文件列表中的文件进行逐个处理,最后转存txt文件。处理完成后监控文件夹应为空,等待下一时次资料的处理。
  自己遇到的问题:
  1、测试的时候,我往监控文件夹复制n个txt文件,结果产生了n次created事件,导致程序被重复处理了n次。
  我想要的结果是:当有多个txt文件被创建时,在一个created事件中处理所有的文件。
  或是每个created事件都处理相应产生的txt文件,但不知道怎样才能获取到产生created事件的相应文件的文件名。
   
  网上还说,利用created事件对文件进行读写操作,会遇到一些异常,比如其他程序在使用,或是文件还在被创建的过程当中。网上说的解决方法也很复杂,都看不懂。我自己试了下,复制2个txt文件,在created事件中写读整个txt文件,运行正常。可能是我的txt文件比较小吧,但还是想在程序方面做相应处理。
C# code

namespace 文件监控入库
{
    class Program
    {
        static void Main(string[] args)
        {
            string MonitorPath;
            MonitorPath = System.Environment.CurrentDirectory+"\\待入库文件1";
            WatcherStrat(@MonitorPath , "*.txt");
            Console.ReadKey();
        }
        private static void WatcherStrat(string path, string filter)        
        {            
            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = path; //不知道怎么设置监控多个目录
            watcher.Filter = filter;
            watcher.Created += new FileSystemEventHandler(OnCreated);
            watcher.EnableRaisingEvents = true;
        }            
          
        private static void OnCreated(object source, FileSystemEventArgs e)
        {             
        
            //获取程序当前路径和文件列表
            string filedir, filepath;
            string[] filelist;
            filedir = System.Environment.CurrentDirectory + "\\待入库文件1";

            DirectoryInfo dir = new DirectoryInfo(filedir); //实例化directoryInf类
            FileSystemInfo[] f = dir.GetFileSystemInfos(); //获取监控目录下的文件名称
            filelist = new string[f.Length];
            for (int i=0;i<f.Length ;i++) 
            {
                filelist[i] = filedir + "\\"+f[i].ToString () ;
                Console.WriteLine(filelist[i]);//输出文件名,调试用的,看正不正常
                RedData(filelist[i].ToString ());//相应文件读取函数
            }
   

        }
        
        public static void RedData(string filepath)
        {
            //读取单个文件  测试
            StreamReader sr = new StreamReader(filepath );
            while (sr.ReadLine ()!=null )
            {
                
                Console .WriteLine (sr.ReadLine ().ToString ());
            }
            sr.Close();
            //将读取的资料写入数据库
            //............
        }
        public static void CopyFile(string filepath)
        {
            //复制转移已入库报文
        }
    }
}



------解决方案--------------------
RedData 写法也不对,ReadLine 是立即返回的,不能 while 条件里调用一次,内部再调用一次,这样不仅漏掉一半,而且很可能条件里能返回,循环内就结束返回 null 了,这时再调用 ToString 就 NullReferenceException 异常,假如文件大,可能写的那边还没完,这边就开始读,出现“该进程无法访问该文件”,可以等待并重试一些次数
C# code
public static void RedData(string filepath)
{
    Stream stream;
    int index = 0;
    while (true)
    {
        try
        {
            stream = File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.None);
            break;
        }
        catch (Exception)
        {
            if (index++ > 5)
            {
                throw;
            }
            else
            {
                Thread.Sleep(1000);
            }
        }
    }

    //读取单个文件  测试
    StreamReader sr = new StreamReader(stream);
    string tr = null;
    while ((tr = sr.ReadLine()) != null)
    {
        Console.WriteLine(tr);
    }
    sr.Close();
    stream.Dispose();
    //将读取的资料写入数据库
    //............
}