Как обрабатывать одновременный доступ к файлам с помощью файлового потока / streamwriter?

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

Проблема в том, что когда два пользователя обновляют этот файл аудита одновременно, «старое значение» каждой переменной смешивается между пользователями. Почему это так и как здесь решить проблему параллелизма?

Какой-то код, сокращенный для краткости ...

Dim fs As FileStream
Dim w As StreamWriter

Public Sub WriteAudit(ByVal filename As String, ByVal username As String, ByVal oldAddress As String, ByVal newAddress As String, ByVal oldCity As String, ByVal newCity As String)
    Dim now As DateTime = DateTime.Now
    Dim audit As String = ""
    audit += now + "," + username + "," + oldAddress + "," + newAddress + "," + oldCity + "," + newCity

    fs = New FileStream(filename, FileMode.Append)
    w = New StreamWriter(fs)
    w.WriteLine(audit)
    w.Close()
    fs.Close()
End Sub

Он находится в классе AuditLogger, на который ссылается переменная экземпляра (перераспределяется при каждом доступе к функции).


person Community    schedule 10.12.2009    source источник
comment
Какая операционная система является сервером, на котором это работает? (Вы можете использовать транзакционную файловую систему.)   -  person Dave Mateer    schedule 10.12.2009


Ответы (3)


Вы можете попробовать это:

TextWriter tw = TextWriter.Synchronized(File.AppendText(filePath));

Метод File.AppendText () возвращает объект StreamWriter, который метод TextWriter.Synchronized () обертывает для создания потокобезопасного TextWriter, который можно использовать так же, как StreamWriter.

person Robert Harvey    schedule 10.12.2009
comment
Будет ли это работать, если экземпляр AuditLogger перераспределяется каждый раз, как указано в вопросе? - person Dave Mateer; 10.12.2009
comment
Не знаю, не пробовал. Теперь, когда я подумал, замок, наверное, не стал бы. Отредактирую ответ. В документации Synchronized Streamwriter только сказано, что он делает StreamWriter потокобезопасным; он ничего не говорит о параллелизме файлов. - person Robert Harvey; 10.12.2009

Реорганизуйте приложение, чтобы вам не приходилось каждый раз создавать новый экземпляр класса AuditLogger. Используйте непосредственно одноэлементный шаблон или dependency-injection, чтобы использовать один и тот же экземпляр во всем приложении.

Оттуда реализация намного проще: окружите операции записи операторами lock или используйте TextWriter.Synchronized, как было упомянуто в ответе Роберта.

Этот пост может быть актуальным:

person Dave Mateer    schedule 10.12.2009
comment
+1 Хороший ответ. Относитесь к нему как к лесорубу. Есть много таких, которые работают так, как должны. - person Robert Harvey; 11.12.2009
comment
Проблема, которая здесь НЕ решается, заключается в том, что несколько процессов пытаются записать в один и тот же файл. - person Mose; 01.12.2010

Пару способов:

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

Во-вторых, можно ли использовать отдельный файл для каждого пользователя? может храниться в их папке% APPDATA%? Или может где-нибудь в сетевом ресурсе?

person Goyuix    schedule 10.12.2009
comment
К сожалению, я не могу сделать ни то, ни другое. Требуется, чтобы база данных не использовалась и была сохранена в файле .csv. Это должен быть централизованный аудит для каждого пользователя, а не индивидуальный для тысяч людей, использующих его. Этот аудит предназначен для руководства, а не для личного пользования. - person ; 10.12.2009
comment
Запись нескольких файлов процесса проблематична - обычно ОС предпочитает, чтобы один процесс управлял записью для одного дескриптора. Также CSV - это база данных, очень простая. У вас есть общая служба, с которой приложение связывается для ведения журнала? Для меня это звучит как несколько необоснованная просьба руководства / уполномоченного сделать это неправильно. Всего два цента. - person Goyuix; 11.12.2009