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