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

.NetFileStreamreaderReadonly

.Net Problem Overview


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 unless I've already got the file open in Excel in which case I get an IOException:

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

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.

.Net Solutions


Solution 1 - .Net

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.ReadWrite parameter.

The FileShare param is often misunderstood. It indicates what other openers 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.

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 only for Read." If you specify FileShare.Read on a file that is open for writing by Excel, your open will fail, as it would violate the constraint, because Excel has it open for writing.

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

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".

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.

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.

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.FileShare is 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.

Solution 2 - .Net

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.

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 CreateFile function. 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

Solution 3 - .Net

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.

Solution 4 - .Net

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

Solution 5 - .Net

Using the System.Diagnostics;

You can simply call 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJon CageView Question on Stackoverflow
Solution 1 - .NetCheesoView Answer on Stackoverflow
Solution 2 - .NetJaredParView Answer on Stackoverflow
Solution 3 - .NetsipsorceryView Answer on Stackoverflow
Solution 4 - .NetDespertarView Answer on Stackoverflow
Solution 5 - .NetDazManCatView Answer on Stackoverflow