如何锁定文件并避免在写入时读取

vto*_*ola 8 .net c# multithreading synchronization filestream

我的Web应用程序从文件系统返回一个文件.这些文件是动态的,所以我无法知道它们中有多少个.当此文件不存在时,应用程序将从数据库中创建该文件.我想避免两个不同的线程同时重新创建相同的文件,或者一个线程尝试在其他线程创建它时返回该文件.

此外,我不想锁定所有文件常见的元素.因此,我应该在创建文件时锁定文件.

所以我想锁定一个文件,直到它的重新创建完成,如果其他线程试图访问它...它将不得不等待文件被解锁.

我一直在阅读关于FileStream.Lock,但我必须知道文件长度,它不会阻止其他线程尝试读取文件,因此它不适用于我的特定情况.

我一直在阅读有关FileShare.None的内容,但是如果其他线程/进程尝试访问该文件,它会抛出一个异常(哪种异常类型?)所以我应该开发一个"在故障时再试一次",因为我我想避免异常生成...我不太喜欢这种方法,尽管可能没有更好的方法.

使用FileShare.None的方法或多或少会:

    static void Main(string[] args)
    {
        new Thread(new ThreadStart(WriteFile)).Start();
        Thread.Sleep(1000);
        new Thread(new ThreadStart(ReadFile)).Start();

        Console.ReadKey(true);
    }

    static void WriteFile()
    {
        using (FileStream fs = new FileStream("lala.txt", FileMode.Create, FileAccess.Write, FileShare.None))
        using (StreamWriter sw = new StreamWriter(fs))
        {
            Thread.Sleep(3000);
            sw.WriteLine("trolololoooooooooo lolololo");
        }
    }

    static void ReadFile()
    {
        Boolean readed = false;
        Int32 maxTries = 5;

        while (!readed && maxTries > 0)
        {
            try
            {
                Console.WriteLine("Reading...");
                using (FileStream fs = new FileStream("lala.txt", FileMode.Open, FileAccess.Read, FileShare.Read))
                using (StreamReader sr = new StreamReader(fs))
                {
                    while (!sr.EndOfStream)
                        Console.WriteLine(sr.ReadToEnd());
                }
                readed = true;
                Console.WriteLine("Readed");
            }
            catch (IOException)
            {
                Console.WriteLine("Fail: " + maxTries.ToString());
                maxTries--;
                Thread.Sleep(1000);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

但我不喜欢这样一个事实:我必须抓住异常,尝试几次并等待不准确的时间:|

Han*_*ant 3

您可以通过使用流构造函数的 FileMode.CreateNew 参数来处理此问题。其中一个线程将丢失并发现该文件已由另一个线程提前一微秒创建。并且会得到一个IOException。

然后它需要旋转,等待文件完全创建。您可以通过 FileShare.None 强制执行。这里捕获异常并不重要,无论如何它都会旋转。无论如何,除非您 P/Invoke,否则没有其他解决方法。