如何对也在Excel中打开的文件执行File.ReadAllLines?
如何在没有IOexception的情况下将Excel中打开的文本文件的所有行读入string[]
?
有一个问题可能是答案的一部分,虽然我不知道如何使用那里的内容: 如何使用.net StreamReader打开已经打开的文件?
您的问题是Excel以读/写方式打开文件。 File.ReadAllLines()
在打开以便在另一个应用程序中写入时无法访问该文件。 如果您在Excel中以只读方式打开csv,则不会遇到此exception。
这是因为.Net中的实现不会打开具有适当权限的内部流,以便在另一个应用程序具有写入权限时访问该文件。
所以这里的修复很简单,编写自己的ReadAllLines()
方法,在启动底层Stream
时设置适当的权限。
这是一个从ReadAllLines()
自己的工作中借鉴的想法:
public string[] WriteSafeReadAllLines(String path) { using (var csv = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var sr = new StreamReader(csv)) { List file = new List (); while (!sr.EndOfStream) { file.Add(sr.ReadLine()); } return file.ToArray(); } }
这与ReadAllLines
所做的唯一区别是FileShare
权限设置为FileShare.ReadWrite
,即使在另一个应用程序中打开了读/写权限,也允许打开该文件。
现在,您必须了解由此产生的问题,因为可能存在复杂性,因为另一个应用程序对文件具有写入权限。
- 您将要阅读上次保存的文件版本,因此如果您在Excel中有未保存的更改,则此方法将不会读取它们
- 如果将此文件保存在Excel中,而此方法正在读取它,则根据具体情况可能会出现exception。 这是因为文件在保存时完全被锁定,因此如果您在锁定文件时尝试读取该文件,则会抛出
System.IO.IOException
。 - 如果您保存文件并设法避免exception(极不可能,但可能给定特定时间),您将读取新保存的文件,而不是原始文件。
要理解为什么在打开其他应用程序编写文件时无法读取该文件,您必须查看.NET中的实际实现。 (这是.Net 4.5中的实现,因此如果您正在查看.Net的差异版本,可能会略有不同)。
这就是File.ReadAllLines()
实际上是这样的:
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 list = new List (); using (StreamReader streamReader = new StreamReader(path, encoding)) { string str; while ((str = streamReader.ReadLine()) != null) list.Add(str); } return list.ToArray(); }
并查看StreamReader
在内部执行的操作:
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); }
所以在这里我们得出抛出exception的原因,当提供路径时, StreamReader
创建一个FileShare
参数设置为Read
的FileStream
。 这意味着它无法与具有该文件的读/写访问权限的另一个应用程序共享文件。 要覆盖此行为,您需要为其提供一个具有不同FileShare
设置的Stream
,这是我在上面提供的解决方案中所做的。
试试这个。
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, System.IO.FileShare.ReadWrite)
只有在读取限制打开时才能打开文件进行读取。 否则,包括ReadAllLines
在内的所有方法都可以在不抛出权限exception的情