58

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.

5 Answers 5

169

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.

3
  • 1
    What a great explanation!!! Thanks Cheeso, my project was coming down to the wire with this issue still open...but not anymore...
    – w4ik
    Commented Apr 6, 2010 at 22:30
  • Very useful! Created a function based on this with two consecutive try catch statements to safely open a document that is already in use in Word or Excel. Thre first attempts to open with FileShare.Read, the second with FileShare.ReadWrite Commented Aug 8, 2013 at 9:54
  • After you get the FileStream you can the use StreamReader with it. See stackoverflow.com/a/286556/492
    – CAD bloke
    Commented Jan 8, 2015 at 0:42
16

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

7
  • I tried your suggestion, but it looks like excel doesn't play nicely (suprise!). Surely it must be possible to open the file though if other programs are capable of doing so?
    – Jon Cage
    Commented May 22, 2009 at 13:27
  • @Jon unfortunately if the other process did not open the file with the equivalent of FileShare.Read then there is no way for you to open the file until that process closes it. The way other programs are able to do this is by opening with FileShare.Read. Office is somewhat notable for opening with exclusive access and preventing other people from reading the file.
    – JaredPar
    Commented May 22, 2009 at 13:33
  • 2
    @Jared: Maybe I didn't make that last point clear. Notepad++ is able to open the file despite it being open already in excel but my C# test bench fails. So it is possible but maybe not using a StreamReader?
    – Jon Cage
    Commented May 22, 2009 at 13:43
  • @Jon interesting. I don't think StreamReader is the issue as it sounds like you're getting an error on the managed version of CreateFile. I'm going to play around with this for a second and see if I can figure it out
    – JaredPar
    Commented May 22, 2009 at 13:48
  • 1
    @Jon, updated my answer. Use FileShare.ReadWrite instead of FileShare.Read. You need to match the implicit sharing setup by the other process. In this case they are sharing reads and writes
    – JaredPar
    Commented May 22, 2009 at 13:54
5

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.

1
  • Not the nicest solution, but in light of any other options, I might be tempted to resort to this - thanks
    – Jon Cage
    Commented May 22, 2009 at 13:28
0

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.

-6

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.

1
  • 2
    -1: That launches an external program to read the file and doesn't help me open it so that I can read the contents in my own programs.
    – Jon Cage
    Commented Nov 29, 2012 at 14:16

Not the answer you're looking for? Browse other questions tagged or ask your own question.