【问题标题】:FileSystemWacher is locking some filesFileSystemWacher 正在锁定一些文件
【发布时间】:2018-12-18 22:44:11
【问题描述】:

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

        _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.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 保持该文件处于打开状态。我不知道为什么,但似乎正在发生这种情况。

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

对此有什么帮助吗?

谢谢 詹姆

【问题讨论】:

  • Jaime,我假设这些是外部写入的文件,您正在监视它们。很可能该文件已被锁定以进行写操作。建议您在代码中添加重试机制并过滤异常类型。在 I/O 代码中遇到这些问题并不罕见。
  • 您可以添加延迟。 Thread.Sleep 并再次检查..看我的答案,
  • @PaulThomas 你是对的......这是一台扫描文档并将其放置在该文件夹中的打印机。奇怪的是,这并不总是发生,而只是随机发生。也许打印机在写入文件时没有关闭文件?我可以在我的程序中做些什么?
  • Jamie, @Guaravsa 在下面提供了一个合适的答案。建议您朝着这个方向前进,并记住 I/O 始终需要弹性代码方法。假设它会第一次失败:)

标签: c# filesystemwatcher


【解决方案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
        }
    }

【讨论】:

  • 但是我用这个赢得了什么?我需要处理文件,而不仅仅是知道文件是否被锁定。
  • 处理文件是什么意思?
  • 文件是否被监控,然后从一个目录移动到另一个目录?
  • 我理解你的意思......你的代码将在新文件的实际过程之前被调用以确保它被关闭,对吗?但是,正如我所意识到的那样,该文件永远不会关闭....但只有当我退出我的控制台应用程序然后再次打开时。
  • 知道了。那么 filesystemwatcher 可能不适合你,因为在文件被扫描到文件夹后你确实需要一些延迟。
猜你喜欢
  • 1970-01-01
  • 2017-10-16
  • 1970-01-01
  • 1970-01-01
  • 2013-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-29
相关资源
最近更新 更多