Как открыть уже открытый файл с помощью.net StreamReader?

У меня есть несколько файлов.csv, которые я использую как часть тестового стенда. Я могу открыть их и прочитать их без каких-либо проблем, если у меня уже нет открытого файла в Excel, в этом случае я получаю IOException:

System.IO.IOException: процесс не может получить доступ к файлу TestData.csv, потому что он используется другим процессом.

Это фрагмент с тестового стенда:

using (CsvReader csv = new CsvReader(new StreamReader(new FileStream(fullFilePath, FileMode.Open, FileAccess.Read)), false))
{
    // Process the file
}

Это ограничение StreamReader? Я могу открыть файл в других приложениях (например, Notepad++), чтобы это не было проблемой O/S. Может быть, мне нужно использовать какой-то другой класс? Если кто-нибудь знает, как я могу обойти это (кроме закрытия Excel!), Я был бы очень благодарен.

5 ответов

Решение

Как говорит Джаред, Вы не можете сделать это, если другой объект, у которого есть открытый файл, не разрешает совместное чтение. Excel допускает совместное чтение, даже для файлов, открытых для записи. Поэтому вы должны открыть файловый поток с параметром FileShare.ReadWrite.

Параметр FileShare часто неправильно понимают. Это указывает на то, что могут делать другие средства открытия файла. Это относится как к прошлым, так и к будущим новичкам. Думайте о FileShare не как о ретроактивном запрете на предыдущие открытия (например, в Excel), а как об ограничении, которое не должно нарушаться при текущем Открытии или любых будущих Открытиях.

В случае текущей попытки открыть файл, FileShare.Read говорит: "Откройте этот файл для меня успешно, только если он любой из предыдущих открывателей открыл его только для чтения". Если вы укажете FileShare.Read для файла, который открыт для записи в Excel, ваше открытие завершится неудачно, так как это нарушит ограничение, потому что в Excel он открыт для записи.

Поскольку в Excel файл открыт для записи, вы должны открыть файл с помощью FileShare.ReadWrite, если хотите, чтобы открытие было успешным. Еще один способ думать о параметре FileShare: он определяет "доступ к файлу другого пользователя".

Теперь предположим другой сценарий, в котором вы открываете файл, который в данный момент не открывается ни одним другим приложением. FileShare.Read говорит, что "будущие новички могут открыть файл только с правами чтения".

Логически, эта семантика имеет смысл - FileShare.Read означает, что вы не хотите читать файл, если другой парень уже пишет его, и вы не хотите, чтобы другой парень писал файл, если вы уже читаете его. FileShare.ReadWrite означает, что вы готовы прочитать файл, даже если другой парень пишет его, и у вас нет проблем, позволяя другому новичку записать файл, пока вы его читаете.

Ни в коем случае это не позволяет нескольким авторам. FileShare похож на базу данных IsolationLevel. Ваше желаемое значение здесь зависит от требуемых гарантий "согласованности".

Пример:

using (Stream s = new FileStream(fullFilePath, 
                                 FileMode.Open,
                                 FileAccess.Read,
                                 FileShare.ReadWrite))
{
  ...
}

или же,

using (Stream s = System.IO.File.Open(fullFilePath, 
                                      FileMode.Open, 
                                      FileAccess.Read, 
                                      FileShare.ReadWrite))
{
}

Приложение:

Документация по System.IO.FileShare немного скудна. Если вы хотите получить прямые факты, перейдите к документации по функции Win32 CreateFile, которая лучше объясняет концепцию FileShare.

РЕДАКТИРОВАТЬ

Я до сих пор не уверен на 100%, почему это ответ, но вы можете решить эту проблему, передав FileShare.ReadWrite в конструктор FileStream.

using (CsvReader csv = new CsvReader(new StreamReader(new FileStream(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)), false)
{
  ...
}

На данный момент мое любопытство охватывает меня, и я пытаюсь понять, почему это именно тот ответ. Если я выясню это позже, я обновлю это информацией.

На самом деле лучшая документация находится в функции CreateFile. Эта функция.Net будет вызываться изнутри, чтобы открыть файл (создать файл - это немного неправильно). В нем есть лучшая документация о том, как работает совместный аспект открытия файла. Другой вариант - просто прочитать ответ Cheeso.

Если другой процесс открыл файл, вы часто можете использовать File.Copy, а затем открыть копию. Не элегантное решение, а прагматичное.

Другой улов в том, что если вы откроете FileStream с FileShare.ReadWriteпоследующие открытия этого файла также должны указывать FileShare.ReadWrite, или вы получите сообщение об ошибке "Другой процесс использует этот файл".

Использование системы. Диагностика;

Вы можете просто вызвать Process.Start("имя файла и путь")

Не уверен, поможет ли это, но это то, что я только что использовал для реализации кнопки "Просмотр PDF" в нашей интрасети.

Другие вопросы по тегам