В C #, если 2 процесса читают и записывают в один и тот же файл, каков наилучший способ избежать исключений блокировки процессов? - PullRequest
25 голосов
/ 21 октября 2008

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

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 , чтобы узнать, когда файл изменился.

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

Ответы [ 8 ]

34 голосов
/ 21 октября 2008

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

Например,

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.
}

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

6 голосов
/ 21 октября 2008

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

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

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

3 голосов
/ 21 октября 2008

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

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

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

2 голосов
/ 21 октября 2008

Читатель и писатель оба нуждаются в механизмах повтора. Также 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();
}
2 голосов
/ 21 октября 2008

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

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

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

2 голосов
/ 21 октября 2008

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

1 голос
/ 08 мая 2013

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

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

1 голос
/ 21 октября 2008

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

...