【问题标题】:How do I open an already opened file with a .net StreamReader?如何使用 .net StreamReader 打开已打开的文件?
【发布时间】:2010-10-28 05:19:27
【问题描述】:

我有一些 .csv 文件用作测试台的一部分。我可以毫无问题地打开它们并阅读它们除非我已经在 Excel 中打开了文件,在这种情况下我会收到 IOException:

System.IO.IOException : 该进程无法访问文件“TestData.csv”,因为它正被另一个进程使用。

这是来自测试台的 sn-p:

using (CsvReader csv = new CsvReader(new StreamReader(new FileStream(fullFilePath, FileMode.Open, FileAccess.Read)), false))
{
    // Process the file
}

这是 StreamReader 的限制吗?我可以在其他应用程序(例如 Notepad++)中打开该文件,所以它不会是操作系统问题。也许我需要使用其他课程?如果有人知道我如何解决这个问题(除了关闭 excel!),我将非常感激。

【问题讨论】:

    标签: .net file streamreader readonly


    【解决方案1】:

    正如 Jared 所说,除非打开文件的其他实体允许共享读取,否则您无法执行此操作。 Excel 允许共享读取,即使对于它已打开以供写入的文件也是如此。因此,您必须使用 FileShare.ReadWrite 参数打开文件流。

    FileShare 参数经常被误解。它指示文件的 other 打开器可以做什么。它适用于过去和未来的开场白。不应将 FileShare 视为对先前打开器(例如 Excel)的追溯性禁令,而是当前打开或任何未来打开都不得违反的约束。

    在当前尝试打开文件的情况下,FileShare.Read 表示“只有在任何先前的打开者为读取而打开此文件时,才能成功为我打开此文件。”如果您在 Excel 为写入而打开的文件上指定 FileShare.Read,您的打开将失败,因为它违反了约束,因为 Excel 已将它打开 用于写入 .

    由于 Excel 已打开文件以进行写入,因此如果您希望 您的 成功打开,您必须使用 FileShare.ReadWrite 打开文件。考虑 FileShare 参数的另一种方式:它指定“其他人的文件访问权限”。

    现在假设一个不同的场景,您正在打开一个当前未被任何其他应用程序打开的文件。 FileShare.Read 说“未来的开启者只能通过读取权限打开文件”。

    从逻辑上讲,这些语义是有意义的 - FileShare.Read 意味着,如果其他人已经在写文件,你不想读取文件,如果你已经在写文件,你不想让其他人写文件阅读它。 FileShare.ReadWrite 意味着,即使其他人正在编写文件,您也愿意读取文件,并且在您读取文件时让其他打开者写入文件也没有问题。

    在任何情况下,这都不允许多个作者。 FileShare 类似于数据库 IsolationLevel。您在此处所需的设置取决于您需要的“一致性”保证。

    例子:

    using (Stream s = new FileStream(fullFilePath, 
                                     FileMode.Open,
                                     FileAccess.Read,
                                     FileShare.ReadWrite))
    {
      ...
    }
    

    或者,

    using (Stream s = System.IO.File.Open(fullFilePath, 
                                          FileMode.Open, 
                                          FileAccess.Read, 
                                          FileShare.ReadWrite))
    {
    }
    

    附录:

    documentation on System.IO.FileShare 有点苗条。如果您想获得直接的事实,请转至the documentation for the Win32 CreateFile function,它更好地解释了 FileShare 概念。

    【讨论】:

    • 多么棒的解释啊!!!谢谢 Cheeso,我的项目即将结束,这个问题仍然存在......但不再......
    • 非常有用!基于此创建了一个函数,其中包含两个连续的 try catch 语句,以安全地打开已在 Word 或 Excel 中使用的文档。第一次尝试使用FileShare.Read 打开,第二次尝试使用FileShare.ReadWrite 打开
    • 获得 FileStream 后,您可以使用 StreamReader。见stackoverflow.com/a/286556/492
    【解决方案2】:

    编辑

    我仍然不能 100% 确定为什么这是答案,但您可以通过将 FileShare.ReadWrite 传递给 FileStream 构造函数来解决此问题。

    using (CsvReader csv = new CsvReader(new StreamReader(new FileStream(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)), false)
    {
      ...
    }
    

    此刻我的好奇心控制住了我,我试图理解为什么这是特定的答案。如果我以后弄明白,我会用信息更新它。

    最好的文档实际上似乎在CreateFile 函数中。这是 .Net 将在后台调用以打开文件的函数(创建文件有点用词不当)。它对打开文件的共享方面的工作方式有更好的文档。另一种选择是阅读 Cheeso 的答案

    【讨论】:

    • 我尝试了你的建议,但看起来 excel 不能很好地发挥作用(惊喜!)。如果其他程序能够打开文件,肯定可以打开文件吗?
    • @Jon 不幸的是,如果其他进程没有打开文件与 FileShare.Read 等效,那么在该进程关闭文件之前,您无法打开文件。其他程序能够做到这一点的方式是使用 FileShare.Read 打开。 Office 以独占访问权限打开并阻止其他人阅读文件有些值得注意。
    • @Jared:也许我没有把最后一点说清楚。 Notepad++ 能够打开文件,尽管它已经在 excel 中打开,但我的 C# 测试台失败。所以它可能但可能不使用 StreamReader?
    • @Jon 很有趣。我认为 StreamReader 不是问题,因为听起来您在 CreateFile 的托管版本上遇到错误。我打算玩一会,看看能不能弄明白
    • @Jon,更新了我的答案。使用 FileShare.ReadWrite 而不是 FileShare.Read。您需要匹配其他进程的隐式共享设置。在这种情况下,他们共享读取和写入
    【解决方案3】:

    如果另一个进程打开了文件,您通常可以使用 File.Copy 然后打开副本。不是优雅的解决方案,而是务实的解决方案。

    【讨论】:

    • 不是最好的解决方案,但鉴于任何其他选择,我可能会想诉诸于此 - 谢谢
    【解决方案4】:

    另一个问题是,如果您使用FileShare.ReadWrite 打开FileStream,随后打开该文件还必须指定FileShare.ReadWrite,否则您将收到“另一个进程正在使用此文件”错误。

    【讨论】:

      【解决方案5】:

      使用 System.Diagnostics;

      您可以简单地调用 Process.Start(“文件名&路径”)

      不确定这是否有帮助,但这就是我刚刚用来在我们的 Intranet 上实现预览 PDF 按钮的方法。

      【讨论】:

      • -1:这会启动一个外部程序来读取文件,但不能帮助我打开它,以便我可以读取自己程序中的内容。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多