如何使用 .net StreamReader 打开已打开的文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/897796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:44:22  来源:igfitidea点击:

How do I open an already opened file with a .net StreamReader?

.netfilestreamreaderreadonly

提问by Jon Cage

I have some .csv files which I'm using as part of a test bench. I can open them and read them without any problems unlessI've already got the file open in Excel in which case I get an IOException:

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

System.IO.IOException : The process cannot access the file 'TestData.csv' because it is being used by another process.

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

This is a snippet from the test bench:

这是测试台上的一个片段:

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

Is this a limitation of StreamReader? I can open the file in other applications (Notepad++ for example) so it can't be an O/S problem. Maybe I need to use some other class? If anyone knows how I can get round this (aside from closing excel!) I'd be very grateful.

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

回答by Cheeso

As Jared says, You cannot do this unless the other entity which has the file open allows for shared reads. Excel allows shared reads, even for files it has open for writing. Therefore, you must open the filestream with the FileShare.ReadWriteparameter.

正如 Jared 所说,除非打开文件的其他实体允许共享读取,否则您不能这样做。Excel 允许共享读取,即使对于它已打开用于写入的文件也是如此。因此,您必须使用FileShare.ReadWrite参数打开文件流

The FileShare param is often misunderstood. It indicates what otheropeners of the file can do. It applies to past as well as future openers. Think of FileShare not as a retroactive prohibition on prior openers (eg Excel), but a constraint that must not be violated with the current Open or any future Opens.

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

In the case of the current attempt to open a file, FileShare.Read says "open this file for me successfully only if it any prior openers have opened it onlyfor Read." If you specify FileShare.Read on a file that is open for writing by Excel, youropen will fail, as it would violate the constraint, because Excel has it open for writing.

在当前尝试打开文件的情况下,FileShare.Read 表示“仅当任何先前的打开程序仅为读取打开此文件时,才能成功为我打开此文件。” 如果您在 Excel 为写入而打开的文件上指定 FileShare.Read,则您的打开将失败,因为它会违反约束,因为 Excel 已将其打开以进行写入

Because Excel has the file open for writing, you must open the file with FileShare.ReadWrite if you want youropen to succeed. Another way to think of the FileShare param: it specifies "the other guy's file access".

因为Excel打开了该文件的写作,你必须,如果你想打开与FileShare.ReadWrite文件打开成功。考虑 FileShare 参数的另一种方式:它指定“其他人的文件访问权限”。

Now suppose a different scenario, in which you're opening a file that isn't currently opened by any other app. FileShare.Read says "future openers can open the file only with Read access".

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

Logically, these semantics make sense - FileShare.Read means, you don't want to read the file if the other guy is already writing it, and you don't want the other guy to write the file if you are already reading it. FileShare.ReadWrite means, you are willing to read the file even if the another guy is writing it, and you have no problem letting another opener write the file while you are reading it.

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

In no case does this permit multiple writers. FileShare is similar to a database IsolationLevel. Your desired setting here depends on the "consistency" guarantees you require.

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

Example:

例子:

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

or,

或者,

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


Addendum:

附录:

The documentation on System.IO.FileShareis a little slim. If you want to get the straight facts, go to the documentation for the Win32 CreateFile function, which explains the FileShare concept better.

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

回答by JaredPar

EDIT

编辑

I'm still not 100% sure why this is the answer, but you can fix this problem by passing FileShare.ReadWrite to the FileStream constructor.

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

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

My curiosity has a hold of me at the moment and I'm trying to understand why this is the particular answer. If I figure it out later I'll update this with the information.

我的好奇心此刻抓住了我,我试图理解为什么这是一个特殊的答案。如果我稍后弄清楚,我会用信息更新它。

The best documentation actually appears to be in the CreateFilefunction. This is the function .Net will call under the hood in order to open up a file (create file is a bit of a misnomer). It has better documentation for how the sharing aspect of opening a file works. Another option is to just read Cheeso's answer

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

回答by sipwiz

If another process has got a file open you can often use File.Copy and then open the copy. Not an elegant solution but a pragmatic one.

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

回答by Despertar

Another catch is that if you open a FileStreamwith FileShare.ReadWrite, subsequent opens of that file must ALSO specify FileShare.ReadWrite, or you will get the 'Another process is using this file' error.

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

回答by DazManCat

Using the System.Diagnostics;

使用 System.Diagnostics;

You can simply call Process.Start(“filename&Path”)

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

Not sure if that helps but, thats what I've just used to implement a Preview PDF button on our intranet.

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