Подтвердить что ты не робот

Как выполнить File.ReadAllLines в файле, который также открыт в Excel?

Как читать все строки текстового файла, который также открыт в Excel, в string[] без получения исключения IO?

Есть вопрос, который может быть частью ответа, хотя я не знаю, как я мог бы использовать то, что там было: Как открыть уже открытый файл с помощью .net StreamReader?

4b9b3361

Ответ 1

Ваша проблема: Excel открывает файл как чтение/запись. File.ReadAllLines() не может получить доступ к файлу, когда он открыт для записи в другом приложении. Если вы открыли csv в Excel только для чтения, вы не столкнетесь с этим исключением.

Это связано с тем, что реализация в .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, что позволяет открывать файл, даже если он открыт с разрешениями на чтение/запись в другом приложении.

Теперь вам нужно понять проблемы, которые могут возникнуть из-за этого, поскольку могут быть сложности, поскольку у другого приложения есть права на запись в файл.

  • Вы будете читать последнюю сохраненную версию файла, поэтому, если у вас есть несохраненные изменения в 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, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan, Path.GetFileName(path), false, false, checkHost), encoding, detectEncodingFromByteOrderMarks, bufferSize, false);
}

Итак, мы пришли к тому, что исключение - это бросок, когда он снабжен контуром, StreamReader создает FileStream, у которого параметр FileShare установлен на Read. Это означает, что он не может совместно использовать файл с другим приложением с доступом для чтения/записи к файлу. Чтобы отменить это поведение, вам нужно указать Stream с другим параметром FileShare, что я и сделал в вышеприведенном решении.

Ответ 2

Попробуйте это.

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

Ответ 3

Вы не можете открыть файл для чтения, только если он открыт с ограничением чтения. В противном случае все методы, включая ReadAllLines, будут работать без исключения разрешений на доступ.

Ответ 4

Хорошая информация. Я использовал streamreader с параметрами доступа/совместного доступа, как показано выше, для журналов, активно написанных машиной и никогда не испытывающих условия блокировки. Я изучил подход File.ReadAllLines, но я думаю, что буду придерживаться того, что работает, так же как и ваше решение.

Спасибо