如何对也在Excel中打开的文件执行File.ReadAllLines?

use*_*322 17 c# io

如何在string[]不获取IO异常的情况下读取也在Excel中打开的文本文件的所有行?

有一个问题可能是答案的一部分,虽然我不知道如何使用其中的内容: 如何使用.net StreamReader打开已打开的文件?

psu*_*003 42

您的问题是Excel以读/写方式打开文件. File.ReadAllLines()当文件打开以便在另一个应用程序中写入时,无法访问该文件.如果您在Excel中以只读方式打开csv,则不会遇到此异常.

这是因为当另一个应用程序具有对其的写入权限时,.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<string> file = new List<string>();
        while (!sr.EndOfStream)
        {
            file.Add(sr.ReadLine());
        }

        return file.ToArray();
    }
}
Run Code Online (Sandbox Code Playgroud)

这和什么之间的唯一区别ReadAllLines确实是FileShare被设定为许可FileShare.ReadWrite,这使得即使是在另一个应用程序读/写权限打开要打开的文件.

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

  1. 您将要阅读上次保存的文件版本,因此如果您在Excel中有未保存的更改,则此方法将不会读取它们
  2. 如果将此文件保存在Excel中,而此方法处于读取过程中,则可能会根据具体情况获得异常.这是因为文件在保存时完全被锁定,因此如果您在锁定文件时尝试读取该文件,则会抛出该文件System.IO.IOException.
  3. 如果您保存文件并设法避免异常(极不可能,但可能给定特定时间),您将读取新保存的文件,而不是原始文件.

要理解为什么在打开其他应用程序写入文件时无法读取该文件,您必须查看.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();
}
Run Code Online (Sandbox Code Playgroud)

并窥视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);
}
Run Code Online (Sandbox Code Playgroud)

所以下面我们就来之所以例外是罚球,当一条路径被提供,StreamReader创建一个FileStream具有FileShare参数设定Read.这意味着它无法与具有该文件的读/写访问权限的其他应用程序共享文件.要覆盖此行为,您需要为其Stream设置一个不同的设置FileShare,这就是我在上面提供的解决方案中所做的.