Как я могу выполнить атомарную запись/добавление в C# или как открыть файлы с флагом FILE_APPEND_DATA?

В большинстве операционных систем, соответствующих Unix и Posix, выполнение вызова операционной системы open() с O_APPEND указывает ОС, что операции записи должны быть атомарными операциями добавления и записи. При таком поведении для локальных файловых систем, когда вы делаете запись, вы знаете, что она добавляется в конец файла.

Операционные системы Windows поддерживают ту же функциональность, передавая FILE_APPEND_DATA в соответствующем параметре системного вызова Win32 CreateFile().

использованная литература:

http://www.google.com/search?q=msdn+createfile
or: http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx

http://www.google.com/search?q=msdn+IoCreateFileSpecifyDeviceObjectHint
or: http://www.google.com/search?q=msdn+IoCreateFileSpecifyDeviceObjectHint

Моя проблема в том, что я не могу определить, как получить такое поведение в C# с помощью библиотек Net Framework, есть ли способ получить такое поведение с помощью Net Framework? Кстати, я не верю, что использование FileMode.Append дает такое поведение.


person Cameron    schedule 07.12.2009    source источник


Ответы (3)


Используйте одну из перегрузок конструктора FileStream:

new FileStream(FileName, FileMode.Open, FileSystemRights.AppendData,
            FileShare.Write, 4096, FileOptions.None)

FileSystemRights.AppendData соответствует FILE_APPEND_DATA

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

Крошечный пример:

    private void button1_Click(object sender, EventArgs e) {
        Thread t1 = new Thread(DoIt);
        Thread t2 = new Thread(DoIt);
        t1.Start("a");
        t2.Start("b");
        Thread.Sleep(2000);
        Environment.Exit(0);
    }

    private void DoIt(object p) {
        using (FileStream fs = new FileStream(FileName, FileMode.Open, FileSystemRights.AppendData,
            FileShare.Write, 4096, FileOptions.None)) {
            using (StreamWriter writer = new StreamWriter(fs)) {
                writer.AutoFlush = true;
                for (int i = 0; i < 20; ++i)
                    writer.WriteLine("{0}: {1:D3} {2:o} hello", p, i, DateTime.Now);
            }
        }
    }
person Fred Mol    schedule 31.03.2011
comment
Это то же самое, что и использование File.AppendText API? - person Ben; 18.06.2013
comment
Последний параметр конструктора FileStream, 'bufferSize' или 4096 в этом примере, будет верхней границей длины атомарной записи. - person Cameron; 21.03.2015
comment
Судя по всему, FileSystemRights отсутствует в dotnetstandard 2.0. - person silvalli; 25.03.2019
comment
Имеет ли значение, используете ли вы FileMode.Append или FileMode.Open? Open не создаст файл, если он не существует - person Hoppe; 10.02.2021

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

person Giorgi    schedule 29.03.2011

Почему ты не можешь использовать

System.IO.File.AppendAllText("C:\\somefile.txt", "some content");

? Это также потокобезопасный/"атомный" вызов.

person enderminh    schedule 07.12.2009
comment
К сожалению, это не дает атомарной операции, которую я ищу. - person Cameron; 15.12.2009
comment
Выдает исключение IOException с файлом, используемым другим процессом, когда несколько потоков обращаются к файлу. - person IvanH; 16.04.2018