【问题标题】:open file in exclusive mode in C#在 C# 中以独占模式打开文件
【发布时间】:2010-10-15 16:03:16
【问题描述】:

我想以独占模式打开一个文件进行读取,如果该文件已经被其他进程/线程打开,我想收到一个异常。我尝试了以下代码,但不起作用,即使我打开了 foo.txt,我仍然可以到达 Console.WriteLine 语句。有什么想法吗?

static void Main(string[] args)
{
    using (Stream iStream = File.Open("c:\\software\\code.txt", FileMode.Open,
    FileAccess.Read, FileShare.None))
    {
        Console.WriteLine ("I am here");
    }

    return;
}

【问题讨论】:

  • "即使我打开了 foo.txt" -> 你是怎么打开的?
  • 是的,迈赫达德。我打开它,然后执行我的程序,仍然可以读取 Console.WriteLine 语句。有什么想法吗?
  • 带记事本?记事本在运行时不会锁定文件。它读取内存中的文件并在保存时重新打开它以进行写入。
  • 我想达到我的目的(不要操作这个文件,而其他进程/线程打开这个文件),我需要检查一个文件是否被打开,对吗?

标签: c# file io


【解决方案1】:

我建议使用FileAccess.ReadWrite 成员,因为某些文件可能已经打开,但允许您Read 访问该文件。但是,我猜想在非异常情况下,所有为Read/Write 访问打开的文件都不允许您的代码将Write 访问到该文件。

当然(正如 Mehrdad 已经解释过的),如果您使用记事本等编辑器打开文件作为测试,您将无法限制访问,因为记事本根本不会锁定文件。

【讨论】:

  • 谢谢Cerebrus,你是对的,我正在使用记事本打开它并运行我的程序进行测试。检查文件是否打开的任何想法(例如,我希望我的代码能够检查记事本是否已打开它)?
  • 不,我不认为有......除非在尝试随后读取文件的代码中捕获 IOException。
  • 我的情况是,一个线程对文件进行序列化(使用XML序列化),另一个reader线程从这个文件中读取。我不希望阅读器线程在 XML 序列化过程中对该文件进行操作,有什么想法吗?
【解决方案2】:

你所做的是正确的。可能您只是在错误地测试它。您应该使用在文件打开时锁定文件的程序打开它。记事本不行。你可以运行你的应用程序两次来查看:

static void Main(string[] args)
{
    // Make sure test.txt exists before running. Run this app twice to see.
    File.Open("test.txt", FileMode.Open, FileAccess.Read, FileShare.None);
    Console.ReadKey();
}

【讨论】:

  • 感谢 Mehrdad,无论如何要检查文件是否已被其他线程/进程打开?
  • 我认为没有办法找出进程是否打开了文件并正在处理它。从技术上讲,文件在记事本加载到内存后不再打开。我认为这是正确的方法,因为记事本或其他程序无法再次打开它(读取或保存),我认为这很好。
  • 谢谢 Mehrdad,我已经测试过你是正确的。我的情况是,一个线程对文件进行序列化(使用 XML 序列化),另一个读取器线程从这个文件中读取。我不希望阅读器线程在 XML 序列化过程中对该文件进行操作,有什么想法吗?
  • 这已经实现了。如果一个线程正在从文件中读取,你会得到 IOException,如果读取器线程在你写入文件时尝试打开文件,你会得到 IOException。
  • 嗨 Mehrdad,我正在使用 XML 序列化,我不确定是否需要一些特殊设置才能让序列化线程锁定文件,以便在使用 FileShare 时阻塞其他读取器线程。没有?
【解决方案3】:

FileShare.None 仅在另一个进程也打开了文件但不允许共享以供读取时才有效。

记事本和 Visual Studio 等程序不会锁定文本文件。

【讨论】:

  • 感谢 Jakob,无论如何要检查文件是否已被其他线程/进程打开?
  • 嗨 Jakob,我的情况是,一个线程正在对文件进行序列化(使用 XML 序列化),另一个读取器线程从该文件中读取。我不希望阅读器线程在 XML 序列化过程中对该文件进行操作,有什么想法吗?
  • 你是如何序列化的?序列化时,您必须以独占方式打开文件(即 FileAccess.Write 和 FileShare.None)。
  • 对不起,我错了。我所说的序列化在我的情况下并不是 100% 准确的。 (继续)
  • 我的情况是,一个线程正在复制文件(使用 File.Move 方法),另一个线程从文件中读取。我不希望读取器线程在复制过程中读取文件的一部分(这就是我想要独占打开模式的原因),我发布的代码是否解决了这个问题?
【解决方案4】:

你做的是对的。

如果您需要已经打开的所有文件,那么有一种方法可以通过 NtQuerySystemInformation 查看

你可以从http://www.codeproject.com/KB/shell/OpenedFileFinder.aspx得到想法

获取在一个目录中打开的所有文件..无论是否打开都可以扩展为单个文件...

【讨论】:

  • 感谢 lakshmanaraj,我的情况是,一个线程正在序列化(使用 XML 序列化)到文件,另一个读取线程从这个文件中读取。我不希望阅读器线程在 XML 序列化过程中对该文件进行操作,有什么想法吗?
  • 您可以通过设置信号量来锁定文件或执行互斥锁操作
  • 文件名是任意的,所以很难锁定。更多细节,我使用写入线程将任意文件从远程机器复制到本地机器,读取线程将扫描文件夹并读取新文件的信息
  • (续)我的情况是,一个线程正在复制文件(使用 File.Move 方法),而另一个线程正在从文件中读取。我不希望读取器线程在复制过程中读取文件的一部分(这就是我想要独占打开模式的原因),我发布的代码是否解决了这个问题?
  • 是的,文件在复制操作期间被写入时会自动锁定,因此您的代码将无法在复制操作期间从文件中读取。您仍然可以检查 status(file) 和 struct stat->st_mode 将给出文件的共享模式是否可以访问。
【解决方案5】:

通过编写一个打开文件然后等待的简单控制台模式程序来测试它:

static void Main(string args[])
{
    using (FileStream f = File.Open("c:\\software\\code.txt", FileMode.Open, FileAccess.Read, FileShare.None))
    {
        Console.Write("File is open. Press Enter when done.");
        Console.ReadLine();
    }
}

从命令行(或 Visual Studio 的另一个实例)运行该程序,然后运行您的程序。这样,您可以使用不同的 FileMode 和 FileShare 值来确保您的程序在所有情况下都能正确响应。

而且,不,您不必先检查文件是否打开。如果文件已经打开,您的代码应该抛出异常。所以你所要做的就是处理那个异常。

【讨论】:

  • 嗨,吉姆,我的情况是,一个线程正在复制文件(使用 File.Move 方法),另一个线程从文件中读取。我不希望读取器线程在复制过程中读取文件的一部分(这就是我想要独占打开模式的原因),我发布的代码是否解决了这个问题?
  • 是的,您的代码解决了这个问题。如果 File.Move 正在复制它,它将不会打开文件。
  • 吉姆,我怎么知道是否有任何(!)程序正在打开它?无论是记事本还是其他东西。或者我怎么知道它现在是否被复制?
  • @Grienders:如果在此代码示例中调用 File.Open 失败并出现访问冲突异常,则该文件当前已从另一个程序打开。但是,您无法判断是否有人正在使用记事本查看文件,因为记事本会打开文件,将其读入内存,然后关闭文件。如果当前正在复制文件,则执行复制的程序会将其打开。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 2013-03-23
  • 1970-01-01
相关资源
最近更新 更多