StreamWriter Запись символов NUL в конец файла при резком завершении работы системы

Я пишу тестовое приложение для записи текста в текстовый файл с помощью StreamWriter. При выполнении метода WriteLine система резко выключилась. После перезагрузки машины заметил, что в конце файла много символов NUL.

Обыскав множество сайтов, включая MSDN, я не нашел решения этой проблемы.

Может ли кто-нибудь помочь мне решить эту проблему.

Это может быть легко воспроизведено, если мы выполним следующие шаги:

  1. Создайте WindowsApplication и поместите в него кнопку управления.
  2. В обработчике события нажатия кнопки напишите следующий код:

    private void button1_Click (отправитель объекта, EventArgs e)

    {
        string str = "Welcome to the C Sharp programming world with a test application using IO operations.";
        StreamWriter sw = new StreamWriter(fileName, true, Encoding.Unicode, str.Length);
        sw.WriteLine(str);
        sw.Close();        
    } 
    
  3. Запустите приложение и непрерывно нажимайте кнопку (Не делайте этого до выключения машины) и нажмите кнопку Poweroff на ПК.

  4. Перезагрузите ПК и проверьте файл, в нем содержится следующий текст:

Добро пожаловать в мир программирования C Sharp с тестовым приложением, использующим операции ввода-вывода.

Добро пожаловать в мир программирования C Sharp с тестовым приложением, использующим операции ввода-вывода.

Добро пожаловать в мир программирования C Sharp с тестовым приложением, использующим операции ввода-вывода.

Добро пожаловать в мир программирования C Sharp с тестовым приложением, использующим операции ввода-вывода.

Добро пожаловать в мир программирования C Sharp с тестовым приложением, использующим операции ввода-вывода.

Добро пожаловать в мир программирования C Sharp с тестовым приложением, использующим операции ввода-вывода.

НУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛНУЛ

Символы NUL появятся в NotePad++, и мы не сможем увидеть эти символы в обычном NotePad.

Заранее спасибо


person Venkat Jaladanki    schedule 06.06.2012    source источник
comment
+1 за отличный вопрос, формат, объяснение и инструкции по воспроизведению.   -  person sealz    schedule 06.06.2012
comment
Не уверен, насколько это поможет, но может помочь выполнение sw.Flush() перед закрытием. Хотя лучше бы ИБП. :(   -  person Tony Hopkinson    schedule 06.06.2012


Ответы (3)


У меня была такая же проблема с netcore на linux (на малине). Похоже, это какой-то буфер, который не сбрасывается вовремя. (способ StreamWriter.Flush() не помогает).

Обходной путь — установить размер буфера равным размеру данных array.Length и отключить все кэширование с помощью FileOptions.WriteThrough (из msdn :)

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

string str = "Welcome to the C Sharp programming world with a test application using IO operations.";
byte[] data = new UTF8Encoding(true).GetBytes(str);
using (FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write,
                                FileShare.Read, data.Length, FileOptions.WriteThrough))
{                    
    fs.Write(data , 0, data.Length);
}

Для тех, кто пришел с C/C++, он устанавливает флаг posix:

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

Дополнительная информация: SO вопрос

person Ludovic Feltz    schedule 05.08.2020
comment
Я был бы удивлен, если бы WriteThrough действительно это исправил. Это может уменьшить вероятность, но я не думаю, что это делает запись атомарной. Сначала увеличивается размер файла, а затем записываются данные. Я полагаю, что WriteThrough вызывает флеш после этой последовательности. - person usr; 06.09.2020

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

Абсолютного решения этой проблемы не существует.

person sharptooth    schedule 06.06.2012
comment
Я знаю, что это старый пост, но я нашел решение. Размер буфера может быть установлен, а кеши могут быть отключены, чтобы они попадали прямо на диск в нужном размере. - person Ludovic Feltz; 05.08.2020

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

var lines = System.IO.File.ReadAllLines(workingFile.FullName);

//Strip the "null line" from file
if (lines[lines.Length - 1].StartsWith("\0\0\0\0\0"))
{
    System.IO.File.WriteAllLines(workingFile.FullName, lines.Take(lines.Length - 1).ToArray());
}

Что это делает, так это считывает все строки в файле в массив, если последняя строка - это надоедливая строка NUL, код запишет все элементы массива за вычетом последнего элемента (строка NUL)

person user3115848    schedule 26.09.2014