FileSystemWacher 正在锁定一些文件

FileSystemWacher is locking some files

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

        _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\Origen12186.xml
18/12/2018 19:12:10 XML file could not be read -> D:\GestorDocumental\Origen12186.xml. See error log.

如你所见,异常是在"using"指令处抛出的。

如果我看到完整的日志,我可以看到那个文件 1112186.xml 以前从未使用过,所以唯一的机会是 FSW 保持文件打开。我不知道为什么,但似乎正在发生这种情况。

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

请问有什么帮助吗?

谢谢 海梅

我通常使用这种方法来检查文件是否被锁定。我从 Whosebug 中的 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 的新 class(它将注入记录器):

    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
        }
    }