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

В С#, если 2 процесса читают и записывают в один и тот же файл, каков наилучший способ избежать исключений блокировки процесса?

Со следующим кодом чтения файла:

using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
{
    using (TextReader tr = new StreamReader(fileStream))
    {
        string fileContents = tr.ReadToEnd();
    }
}

И следующий код записи файла:

using (TextWriter tw = new StreamWriter(fileName))
{
    tw.Write(fileContents);
    tw.Close();
}

Ниже приводятся сведения об исключении:

Процесс не может получить доступ к файлу 'c:\temp\myfile.txt', потому что это используется другим процессом.

Каков наилучший способ избежать этого? Должен ли читатель повторять попытку после получения исключения или есть лучший способ?

Обратите внимание, что процесс чтения использует FileSystemWatcher, чтобы знать, когда файл был изменен.

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

4b9b3361

Ответ 1

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

Например,

using (FileStream stream = new FileStream(@"C:\Myfile.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
   // Do your writing here.
}

Другой доступ к файлам просто открывает файл для чтения, а не для записи, и позволяет совместное использование readwrite.

using (FileStream stream = new FileStream(@"C:\Myfile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
   // Does reading  here.
}

Если вы хотите, чтобы читатели всегда читали обновленный файл, вам нужно будет использовать файл блокировки, который указывает, что кто-то пишет в файл (хотя вы можете получить условие гонки, если не будете тщательно реализованы ) или убедитесь, что вы блокируете совместное использование писем при открытии для чтения и обработки исключения, чтобы повторить попытку, пока не получите эксклюзивный доступ.

Ответ 2

Если вы создаете именованный Mutex, вы можете определить мьютекс в приложении для записи и попросите приложение чтения до тех пор, пока не будет выпущен мьютекс.

Итак, в процессе уведомления, который в настоящее время работает с FileSystemWatcher, просто проверьте, нужно ли ждать мьютекса, если вы это сделаете, он будет ждать, а затем обработать.

Вот пример VB Mutex, который я нашел, достаточно просто преобразовать в С#.

Ответ 3

Есть ли какая-то особая причина для открытия файла с помощью FileShare.None? Это предотвратит открытие файла любым другим процессом.

FileShare.Write или FileShare.ReadWrite должен разрешить другому процессу (с разрешениями) открывать и записывать в файл во время его чтения, однако вам придется следить за изменением файла под вами, пока вы его читаете - просто буферизация содержимого при открытии может помочь здесь.

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

Ответ 4

Для этого можно использовать объект Mutex.

Ответ 5

Получите ваш процесс, чтобы проверить статус файла, если он записывается. Вы можете сделать это за счет наличия файла блокировки (т.е. Наличие этого другого файла, который может быть пустым, предотвращает запись в основной файл).

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

Если ваш процесс встречает файл блокировки, попробуйте его просто спать/ждать и повторить попытку в предопределенный промежуток времени в будущем.

Ответ 6

Читателю и писателю нужны механизмы повтора. Также FileShare должен быть установлен в FileShare.read для читателей и FileShare.none для писателя. Это должно гарантировать, что читатели не читают файл во время записи.

Читатель (исключая повтор) становится

using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    using (TextReader tr = new StreamReader(fileStream))
    {
        string fileContents = tr.ReadToEnd();
    }
}

Писатель (исключая повтор) становится:

FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
using (TextWriter tw = new StreamWriter(fileStream))
{
    tw.Write(fileContents);
    tw.Close();
}

Ответ 7

Напишите временному файлу, когда закончите запись, переименуйте/переместите файл в нужное место и/или имя, которое читатель ищет.

Ответ 8

Лучшее, что нужно сделать, - это поставить протокол приложения поверх механизма передачи файлов и передачи прав собственности. Механизм "lock-file" - это старый хакер UNIX, который существует уже целую вечность. Лучшее, что нужно сделать, это просто "передать" файл читателю. Есть много способов сделать это. Вы можете создать файл со случайным именем файла, а затем "дать" это имя читателю. Это позволит автору асинхронно писать другой файл. Подумайте, как работает "веб-страница". Веб-страница имеет ссылку на дополнительную информацию в ней, для изображений, сценариев, внешнего контента и т.д. Сервер передает вам эту страницу, потому что это когерентное представление о "ресурсе", который вы хотите. Затем ваш браузер переходит к соответствующему контенту, основываясь на описании страницы (файл HTML или другой возвращаемый контент), а затем передает то, что ему нужно.

Это наиболее устойчивый тип механизма совместного использования. Запишите файл, поделитесь им, перейдите к следующему файлу. Часть "разделять имя" - это атомная рука, которая гарантирует, что обе стороны (читатель и писатель) согласны с тем, что контент "завершен".