How do I read all lines of a text file that is also open in Excel into string[]
without getting IO exception?
There is this question which could be a part of the answer, though I don't know how I could use what's in there: How do I open an already opened file with a .net StreamReader?
ReadLines() will lock the file until it finishes.
Returns. A string array containing all lines of the file.
ReadAllLines(String) is an inbuilt File class method that is used to open a text file then reads all lines of the file into a string array and then closes the file. Syntax: public static string[] ReadAllLines (string path);
Your problem is Excel opens the file as read/write. File.ReadAllLines()
cannot access the file when it is open for writing in another application. If you opened the csv in Excel as read only, you wouldn't encounter this exception.
This is because the implementation in .Net does not open the internal stream with appropriate permissions to access the file when another application has write permissions to it.
So the fix here is simple, write your own ReadAllLines()
method that sets the appropriate permissions when initiating the underlying Stream
.
Here's an idea that borrows heavily from what ReadAllLines()
does on its own:
public string[] WriteSafeReadAllLines(String path)
{
using (var csv = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var sr = new StreamReader(csv))
{
List<string> file = new List<string>();
while (!sr.EndOfStream)
{
file.Add(sr.ReadLine());
}
return file.ToArray();
}
}
The only difference between this and what ReadAllLines
does is the FileShare
permission is set to FileShare.ReadWrite
, which allows the file to be opened even when it is open with Read/Write permissions in another application.
Now, you have to understand the issues that can arise from this as there can be complications since another application has write permissions to the file.
System.IO.IOException
.To understand why you cannot read the file when it is open for writing by another application, you have to look at the actual implementation in .NET. (This is the implementation in .Net 4.5 so it may be slightly different if you are looking at a difference version of .Net).
This is what File.ReadAllLines()
actually looks like:
public static string[] ReadAllLines(string path)
{
if (path == null)
throw new ArgumentNullException("path");
if (path.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
else
return File.InternalReadAllLines(path, Encoding.UTF8);
}
private static string[] InternalReadAllLines(string path, Encoding encoding)
{
List<string> list = new List<string>();
using (StreamReader streamReader = new StreamReader(path, encoding))
{
string str;
while ((str = streamReader.ReadLine()) != null)
list.Add(str);
}
return list.ToArray();
}
And to peek at what StreamReader
is doing internally:
internal StreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool checkHost)
{
if (path == null || encoding == null)
throw new ArgumentNullException(path == null ? "path" : "encoding");
if (path.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
if (bufferSize <= 0)
throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
this.Init((Stream) new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan, Path.GetFileName(path), false, false, checkHost), encoding, detectEncodingFromByteOrderMarks, bufferSize, false);
}
So here we come to the reason why the exception is throw, when supplied with a path, StreamReader
creates a FileStream
that has the FileShare
parameter set to Read
. This means that it cannot share a file with another application with Read/Write access to the file. To override this behavior you need to give it a Stream
with a different setting for FileShare
, which is what I did in the solution I provided above.
You cannot open file for reading only when it is opened with a read restriction. Otherwise all methods including ReadAllLines
will work without throwing permission exceptions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With