Как открыть уже открытый файл с помощью.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" в нашей интрасети.