c# - C# 中的 FileStream 和 FileSystemWatcher,奇怪的问题 "process cannot access the file"

标签 c# filestream filesystemwatcher

我有一个复杂的代码库,它正在监听某个文件夹上的 FileCreated 事件。创建文件后(还包括将文件移动到该文件夹​​),我想读入该文件并对其进行处理。它适用于第一个文件,但在所有其他尝试之后抛出异常。在 Debug模式下(使用 VisualStudio)会抛出错误,但如果我只需单击“继续”......它就会工作(没有错误)。

我已经发布了简化的代码,它演示了这个问题。

比如你启动应用程序,点击“开始”按钮,然后“新建一个文本文件”

输出是:

Working

如果您随后以完全相同的方式创建第二个文件,则输出为:

Broken: The process cannot access the file 'C:\TestFolder\New Text Document (2).txt' because it is being used by another process.
Working, after breaking

在查看我的代码后,您会看到上面的一组打印输出暗示首先抛出了“无法访问文件”异常,但在 catch 语句中执行相同的调用突然起作用了。

这对我来说毫无意义,因为该文件显然没有被其他任何东西使用(我刚刚创建它)..无论如何它会在一秒钟后工作....

下面是我的代码

XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" >
    <StackPanel>
        <Button Click="Button_Click"  Content="Start"/>
    </StackPanel>
</Window>

代码隐藏:

using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;


namespace WpfApplication1
{ 
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            test();
        }


        String Folder = @"C:\TestFolder";

        private void test()
        {
            FileSystemWatcher watch = new FileSystemWatcher(Folder);
            watch.Created += new FileSystemEventHandler(FileCreated);
            watch.EnableRaisingEvents = true;

            Process.Start(Folder);
        }

        private void FileCreated(object sender, FileSystemEventArgs fsEvent)
        {

            if (File.Exists(fsEvent.FullPath))
            {

                // Thread.Sleep(1000);// Sleeping for 1 second seems to prevent the error from happening...?
                // If i am debugging, and pause on exceptions... then it also suddenly works (similar to the Sleep above)
                try
                {

                    FileStream fs = new FileStream(fsEvent.FullPath, FileMode.Open); 
                    Console.WriteLine("Working");
                    fs.Close();
                }
                catch (IOException ex)
                {
                    Console.WriteLine("Broken: " + ex.Message);
                    try
                    {                        
                        FileStream fs = new FileStream(fsEvent.FullPath, FileMode.Open);
                        Console.WriteLine("Working, after breaking");
                        fs.Close();

                    }
                    catch(IOException ex2)
                    {                        
                        FileStream fs = new FileStream(fsEvent.FullPath, FileMode.Open);
                        Console.WriteLine("really broken: " + ex2.Message);
                        fs.Close();
                    }
                }


            }
        }
    }
}

最佳答案

自从 .NET 1.0 以来,我就已经看到了您所描述的行为,但从来没有费心去找出它发生的原因。在您调用关闭和处置后,操作系统或 .NET 有时(?)似乎会在短时间内锁定文件。

我制定了一个变通办法 - 如果您愿意,也可以破解 - 已被证明对我们非常有效。我们每天在服务器场中处理数百万个文件,文件观察器检测到的所有文件在移交给进一步处理之前都会通过此方法。

它的作用是在文件上放置一个独占锁。如果失败,它可以选择等待最多 10 秒,以便在放弃之前关闭文件。

    public static bool IsFileClosed(string filepath, bool wait)
    {
        bool        fileClosed = false;
        int         retries = 20;
        const int   delay = 500; // Max time spent here = 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) {}

            if (!wait) break;

            retries --;

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

        return fileClosed;
    }

关于c# - C# 中的 FileStream 和 FileSystemWatcher,奇怪的问题 "process cannot access the file",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21739242/

相关文章:

c# - WCF REST HttpContext.Current 异步/等待

c++ - ifstream::open() 到底做了什么?

c# - 带有 FileSystemWatcher 的目录扫描器 Windows 服务

c# - 增加 FileSystemWatcher.InternalBufferSize 真的那么昂贵吗?

c# - 应用程序在另一个线程中不会故意崩溃

c# - 使用任何方法在 openTK 应用程序中播放音频的最简单方法

c# - 允许 sorting=false 不起作用?

c# - 以这种方式使用 FileStream.seek 安全吗?

c# - C# 中的 FileStream 是否有可以使用的最大文件大小?

eclipse - 在 Eclipse 中如何使本地 tomcat 服务器重新发布而 Eclipse 不在前台