【问题标题】:Why am I getting a Unhandled Exception: System.IO.IOException when trying to read from a file being written to?为什么我在尝试从正在写入的文件中读取时收到未处理的异常:System.IO.IOException?
【发布时间】:2023-03-17 10:28:01
【问题描述】:

我有两个 C# 应用程序,一个是逐行读取文件(文件 A)并将其内容写入另一个文件(文件 B)。

第二个应用程序使用 FileSystemWatcher 来查看文件 B 的更新时间,并报告程序启动时间和文件更改时间之间的行号差异。

这就是我现在要做的所有事情,最终我想读取文件上次读取时间和当前读取时间之间的行,但直到我可以得到暂停的行差异。

应用程序 1 的代码是;

        static void Main(string[] args)
    {
        String line;

        StreamReader sr = new StreamReader("f:\\watch\\input.txt");

        FileStream fs = new FileStream("f:\\watch\\Chat.log", FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
        StreamWriter sw = new StreamWriter(fs);

        while ((line = sr.ReadLine()) != null)
        {
            sw.WriteLine(line);
            Thread.Sleep(200);
            Console.WriteLine(line);
            sw.Flush();

        }

        sw.Close();
        sr.Close();

    }

应用程序 2 的代码是;

        public static int lines = 0;

    public static void Main()
    {
        Run();
    }

    public static void Run()
    {
        string[] args = System.Environment.GetCommandLineArgs();

        if (args.Length != 2)
        {
            Console.WriteLine("Usage: Watcher.exe (directory)");
            return;
        }

FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = args[1];

watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite 
   | NotifyFilters.FileName | NotifyFilters.DirectoryName;

watcher.Filter = "Chat.log";

watcher.Changed += new FileSystemEventHandler(OnChanged);

watcher.EnableRaisingEvents = true;

lines = File.ReadAllLines(args[1] + "\\Chat.log").Length;

Console.WriteLine("File lines: " + lines);

while(Console.Read()!='q');
}

private static void OnChanged(object source, FileSystemEventArgs e)
{
    Linework(e.FullPath);
    Console.WriteLine("File: " +  e.FullPath + " " + e.ChangeType);
}

public static string Linework(string path)

{



   string newstring = " ";

using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    int newlines = File.ReadAllLines(path).Length;
    Console.WriteLine("Lines now: " + newlines);
}

return newstring;

}

现在,当我尝试同时运行这两个应用程序时,我收到一个异常提示“未处理的异常:System.IO.IOException:该进程无法访问该文件,因为它正在被另一个进程使用”。

我为 ReadWrite 访问设置了两个文件流,我为 FileAccess.Write 设置了一个文件流,为 FileAccess.Read 设置了另一个。

关于我为什么会得到这个异常的任何线索?

谢谢 呵呵。

【问题讨论】:

  • 哪个应用程序出现错误?
  • FileShare.ReadWrite 负责同时打开文件,但这是否也有助于允许同时访问?
  • @apoorv020:是的,即使对于其他进程也是如此。不过,它可能需要额外的权限。
  • @spinon 抱歉,引发异常的应用程序是 FileSystemWatcher 应用程序(应用程序 2)。

标签: c# file filesystemwatcher


【解决方案1】:

lines = File.ReadAllLines(args[1] + "\Chat.log").Length;

你的问题。该方法打开文件,读取所有行并再次关闭它。打开文件 FileShare.Read 时,它使用“正常”文件共享设置。 拒绝对同样打开文件的任何其他进程的写访问。

这不能在这里工作,你已经用写权限打开了文件。第二个过程不能否认它。结果是 IOException。

您不能在此处按原样使用 File.ReadAllLines(),您需要使用 FileShare.ReadWrite 打开 FileStream,将其传递给 StreamReader 并读取所有行。

当心你在这里遇到的非常麻烦的比赛潜力,不能保证你读到的最后一行是完整的。在行尾只得到一个 \r 而不是 \n 是一个特别棘手的问题。这将随机且不频繁地发生,是最难解决的错误。也许你的 Flush() 调用修复了它,我从来没有足够的勇气来测试它。

【讨论】:

  • +1 令人印象深刻。我看到了一些类似的东西,但无法用语言表达。
  • 其他答案中已经写过了。至于阅读,你是对的。他可以使用一个命名的 Mutex 轻松解决这个问题。此外,他并没有真正阅读这些行(就像它们的内容一样),只是计算它们。
  • 谢谢汉斯,我尝试使用 Streamreader,它确实有效,但是我认为读取每一行来计算要比较的总行数效率低下。我将继续这样做,因为我一直在研究如何删除 SafeFileHandles,它似乎不是一个选项。非常感谢。
  • 它与 File.ReadAllLines() 一样高效。没有办法提高效率,只有一种方法可以在后台读取文本文件。无论如何,文件数据都应该从文件系统缓存中出来。
【解决方案2】:

在这种情况下,允许第二个程序 ReadWrite 访问文件将起作用。

//lines = File.ReadAllLines(args[1] + "\\Chat.log").Length;
//Commenting the above lines as this would again open a new filestream on the chat.log
//without the proper access mode required.


    using (FileStream fsReader = new FileStream(args[1] + "\\Chat.log", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
        {
            using (StreamReader sr = new StreamReader(fsReader))
            {
                while (sr.ReadLine() != null)
                    lines++;
            }
        }

【讨论】:

  • +1 正是 OP 需要的。他将使用path 而不是args[1] + "\\Chat.log",因为他已经在范围内定义了它。
【解决方案3】:
StreamReader sr = new StreamReader("f:\\watch\\input.txt");

input.txt 可能无法读取?

还在第一个应用程序中使用using 语句而不是 Close()(以防引发异常)。

否则没关系。文件共享可能需要额外的权限(不会真正影响)。

我漏掉了一段代码:

int newlines = File.ReadAllLines(path).Length;

为此使用streamStreamReader

【讨论】:

  • 感谢有关使用“使用”的提示,我更改了应用程序来做到这一点。权限应该没问题,因为我可以打开 input.txt。我正在运行对系统的完全访问权限。
  • 对于input.txt,我的意思是如果它没有被其他进程打开而不共享。
【解决方案4】:

MSDN 提供了两种不获得独占保留的方法:

FileStream 对象不会有 独占其手柄时 SafeFileHandle 属性是 访问以暴露句柄或 FileStream 对象被赋予 SafeFileHandle 属性在其 构造函数。

文档暗示反之亦然:

在不设置 SafeFileHandle 的情况下打开 FileStream 意味着 FileStream 保持对文件句柄的独占保留(即 与应该抛出的 IO 异常内联)。

【讨论】:

  • SafeHandle 通常由网络 Socket 操作或文件映射公开(在应用程序中不使用公开文件句柄的代码)。文档在哪里暗示了这一点?
  • 它在引用中暗示。反之,当既没有访问 SafeFileHandle 属性以公开句柄,也没有在其构造函数中为 FileStream 对象赋予 SafeFileHandle 属性时,fileStream 对象将独占其句柄。
  • 简单的句子演算:句子 A:FS 不会独占。 句子 B:使用了 SafeFileHandle。 你使用了 (B => A)(~B => ~A) 不等价。 (B => A)(~A => ~B) 是等价的。原句等价于:If SafeFileHandle is used, FS will NOT have an exclusive hold. 所以等价反义为:(SafeFileHandle is NOT used) when (FS has exclusive hold) 相当于:(If FS has exclusive hold), (SafeFileHandle is NOT used)。这意味着您的答案中的句子不正确!
  • 底线 - 文本允许可能即使不使用 SafeHandle,FS 也没有独占保留。
猜你喜欢
  • 1970-01-01
  • 2011-08-03
  • 1970-01-01
  • 2015-12-20
  • 2022-06-17
  • 2013-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多