FileSystemWacher锁定了一些文件

时间:2018-12-18 22:44:11

标签: c# filesystemwatcher

我正在使用此代码来监视某些文件夹中文件的创建:

        _watcher = new RecoveringFileSystemWatcher(SourceFolder, "*.xml"); 

        _watcher.Created += (_, e) =>
        {
            ProcessFile(e.Name);
        };

RecoveringFileSystemWatcher是fileSystemWatcher的包装器。它的构造函数是:

    public RecoveringFileSystemWatcher (string path, string filter)
    {
        _containedFSW = new FileSystemWatcher(path, filter);
    }

该过程按预期工作,但是对于某些文件,随机地,抛出一个异常,表明该文件已被另一个进程使用。

这是在文件创建时启动的方法:

        var nfo = new FileInfo(filePath);
        if (nfo.Exists)
        {
            var archivoXml = nfo.Name;

            string archivo = String.Empty;
            try
            {
                string content = Task.Run(async () => await GetFileContent(filePath)).Result;
                if (String.IsNullOrEmpty(content))
                    return false;

                XmlDocument xml = new XmlDocument();
                xml.LoadXml(content);

                //The rest of the method
             }
         }

GetFileContent方法是这样的:

    private async Task<string> GetFileContent(string filePath)
    {
        string content = String.Empty;

        try
        {
            Console.Write("ONE - "); InfoLog.Save($"ONE {filePath}");
            using (StreamReader sr = new StreamReader(filePath))
            {
                Console.Write("TWO - "); InfoLog.Save($"TWO {filePath}"); 
                content = await sr.ReadToEndAsync().ConfigureAwait(false);
                Console.Write($"THREE {(sr.BaseStream == null ? "Closed" : "Opened")} - "); InfoLog.Save($"THREE {(sr.BaseStream == null ? "Closed" : "Opened")} {filePath}");
                sr.Close();
                Console.WriteLine($"FOUR {(sr.BaseStream == null ? "Closed" : "Opened")}"); InfoLog.Save($"FOUR {(sr.BaseStream == null ? "Closed" : "Opened")} {filePath}");
            }
        }
        catch (Exception ex)
        {
            InfoLog.Save($"XML file could be read -> {filePath}. See error log.");
            ErrorLog.Save(ex);
        }

        return content;
    }

查看我正在编写的用于调试过程的日志信息。

我遇到了一个案例,文件名为1112186.xml。...记录在日志中:

18/12/2018 19:12:10 ONE D:\GestorDocumental\Origen\1112186.xml
18/12/2018 19:12:10 XML file could not be read -> D:\GestorDocumental\Origen\1112186.xml. See error log.

如您所见,在“使用”指令处引发了异常。

如果我看到完整的日志,则可以看到以前从未使用过文件1112186.xml,因此,唯一的机会是FSW保持文件打开。我不知道为什么,但是看来这正在发生。

很明显,此过程正在锁定文件,因为当我退出控制台应用程序然后再次运行时,可以对文件进行处理。

对此有任何帮助吗?

谢谢 海梅

1 个答案:

答案 0 :(得分:1)

我通常使用这种方法来检查文件是否被锁定。我是从stackoverflow中的link之一获得的。

  public static bool IsFileClosed(string filepath)
  {
        bool fileClosed = false;
        int retries = 20;
        const int delay = 400; // set a delay period = 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) { }

            retries--;

            if (!fileClosed)
                Thread.Sleep(delay);
        }
        while (!fileClosed && retries > 0);

        return fileClosed;
    }

这是一个名为FileTimerWatcher的新类(它将注入记录器):

    public FileTimerWatcher(ILogger logger) : base(logger)
    {
        if (timer == null)
        {
            // Create a timer with a 1.5 second interval.
            // monitor the files after 1.5 seconds.
            timer = new Timer(delay);

            // Hook up the event handler for the Elapsed event.
            timer.Elapsed += new ElapsedEventHandler(ProcessFolder);

            timer.AutoReset = true;
            timer.Enabled = true;
        }
    }

    private void ProcessFolder(object sender, ElapsedEventArgs e)
    {
        var LastChecked = DateTime.Now;

        string[] files = System.IO.Directory.GetFiles(SourceDirectory, somefilter, System.IO.SearchOption.TopDirectoryOnly);

        foreach (string file in files)
        {
            ProcessFile(file); // process file here
        }
    }