如何对也在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 ,即使在另一个应用程序中打开了读/写权限,也允许打开该文件。

现在,您必须了解由此产生的问题,因为可能存在复杂性,因为另一个应用程序对文件具有写入权限。

  1. 您将要阅读上次保存的文件版本,因此如果您在Excel中有未保存的更改,则此方法将不会读取它们
  2. 如果将此文件保存在Excel中,而此方法正在读取它,则根据具体情况可能会出现exception。 这是因为文件在保存时完全被锁定,因此如果您在锁定文件时尝试读取该文件,则会抛出System.IO.IOException
  3. 如果您保存文件并设法避免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参数设置为ReadFileStream 。 这意味着它无法与具有该文件的读/写访问权限的另一个应用程序共享文件。 要覆盖此行为,您需要为其提供一个具有不同FileShare设置的Stream ,这是我在上面提供的解决方案中所做的。

试试这个。

 FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, System.IO.FileShare.ReadWrite) 

只有在读取限制打开时才能打开文件进行读取。 否则,包括ReadAllLines在内的所有方法都可以在不抛出权限exception的情