C# · 12月 27, 2021

c# – 如何在Excel中打开的文件上执行File.ReadAllLines?

如何读取也在Excel中打开的文本文件的所有行,以获取IO异常?

有这个问题可能是答案的一部分,虽然我不知道如何使用在那里的内容:
How do I open an already opened file with a .net StreamReader?

解决方法 您的问题是Excel将文件打开为读/写.当File.ReadAllLines()在其他应用程序中打开以进行写入时,无法访问该文件.如果您将Excel中的csv以只读方式打开,则不会遇到此异常.

这是因为在另一个应用程序具有写入权限的情况下,.Net中的实现不会打开具有适当权限的内部流来访问该文件.

所以这里的修复很简单,编写自己的ReadAllLines()方法,在启动底层流时设置适当的权限.

这是一个想法,大大地借鉴了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<string> file = new List<string>(); while (!sr.EndOfStream) { file.Add(sr.ReadLine()); } return file.ToArray(); }}

这与ReadAllLines之间的唯一区别是FileShare权限设置为FileShare.ReadWrite,即使在其他应用程序中使用读/写权限打开时也可以打开该文件.

现在,您必须了解可能出现的问题,因为另一个应用程序对该文件具有写入权限,因此可能会出现并发症.

>您将要阅读上次保存的文件版本,因此如果Excel中有未保存的更改,则此方法将不会读取它们
>如果将文件保存在Excel中,而这种方法正在读取它,您将根据情况可能会获得异常.这是因为文件在保存时被完全锁定,因此如果您在锁定时尝试读取文件,则会抛出一个System.IO.IOException异常.
>如果您保存文件并进行管理以避免异常(极少可能,但可能在具体时间可能的情况下),则要读取新保存的文件,而不是原始文件.

为了理解为什么在另一个应用程序打开该文件时无法读取该文件,您必须查看.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<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();}

并了解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,FileShare.Read,4096,FileOptions.SequentialScan,Path.GetFileName(path),false,checkHost),encoding,detectEncodingFromByteOrderMarks,bufferSize,false);}

所以在这里我们来了解异常抛出的原因,当提供了一个路径时,StreamReader创建一个FileShare参数设置为Read.这意味着它不能与具有对该文件的读/写访问的另一应用程序共享文件.要覆盖此行为,您需要为FileShare提供一个不同设置的Stream,这是我在上面提供的解决方案中所做的.