55

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

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

这是来自测试台的片段:

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

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

4

5 回答 5

165

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

FileShare 参数经常被误解。它指示文件的其他打开器可以做什么。它适用于过去和未来的开场白。不将 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))
{
}

附录:

System.IO.FileShare上的文档有点少。如果您想获得直接的事实,请转到Win32 CreateFile 函数的文档,它更好地解释了 FileShare 概念。

于 2009-05-22T14:05:09.143 回答
16

编辑

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

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

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

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

于 2009-05-22T13:22:00.603 回答
5

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

于 2009-05-22T13:25:04.250 回答
0

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

于 2012-10-05T04:34:41.867 回答
-7

使用 System.Diagnostics;

您可以简单地调用 Process.Start(“filename&Path”)

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

于 2012-11-29T13:16:30.413 回答