19

string[]Excelでも開いているテキストファイルのすべての行を、 IO例外を発生させずに読み込むにはどうすればよいですか?

そこにあるものをどのように使用できるかわかりませんが、答えの一部になる可能性のあるこの質問があります: .net StreamReader で既に開いているファイルを開くにはどうすればよいですか?

4

3 に答える 3

56

あなたの問題は、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();
    }
}

これとの唯一の違い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();
}

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);
}

ここで、例外がスローされる理由に行き着きます。パスを指定すると、パラメーターが に設定された がStreamReader作成されます。これは、ファイルへの読み取り/書き込みアクセス権を持つ別のアプリケーションとファイルを共有できないことを意味します。この動作を無効にするには、 に別の設定を与える必要があります。これは、上記で提供したソリューションで行ったことです。FileStreamFileShareReadStreamFileShare

于 2014-06-21T13:30:43.237 に答える
2

読み取り制限付きでファイルを開いた場合、読み取り専用で開くことはできません。ReadAllLinesそうしないと、許可例外をスローすることなく、すべてのメソッドが機能します。

于 2012-10-05T12:33:29.103 に答える
1

これを試して。

FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read,
System.IO.FileShare.ReadWrite)
于 2012-10-05T10:59:04.000 に答える