Потеря данных при записи файла File.WriteAllLines

161
06 марта 2021, 15:00

Есть файл, в котором находятся данные data1, полное имя с адресом в переменной FullFileName. Я записываю новые данные в данный файл File.WriteAllLines(FullFileName, data2); Если во время выполнения записи произойдет ошибка, ну к примеру закончилось место на носителе, то что произойдет? Файл будет пустой, в нем останутся данные data1, или часть данных data2?

Answer 1

Файл будет пустой, в нем останутся данные data1, или часть данных data2?

Вообще, из-за ошибки записи может произойти и то, и другое и третье:

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

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

Вот пример кода, который симулирует все три варианта развития событий:

using System;
using System.IO;
using System.Linq;
using System.Threading;
class Program
{
    static void Main()
    {
        //записываем три файла с одинаковым текстом
        File.WriteAllText("unchanged", "initial");
        File.WriteAllText("empty", "initial");
        File.WriteAllText("partial", "initial");
        //симулируем ошибки
        //один файл занимаем другим потоком (в реальности может быть другой процесс)
        //запись оборвется при попытке открытия
        var unchangedLock = new FileStream("unchanged", FileMode.Open);
        //в другом блокируем часть файла
        //запись оборвется при попытке записи
        var emptyLock = new FileStream("empty", FileMode.Open,FileAccess.Read, FileShare.ReadWrite);
        emptyLock.Lock(1, 1);
        //запускаем потоки для перезаписи файлов
        var unchangedThread = CreateWriteThread("unchanged");
        var emptyThread = CreateWriteThread("empty");
        var partialThread = CreateWriteThread("partial");
        //дожидаемся завершения записи
        unchangedThread.Join();
        emptyThread.Join();
        //запись третьего файла обрывается посередине
        //по каким-то причинам, например, из-за нехватки места на диске
        partialThread.Abort();
        //освобождаем файлы чтобы прочитать
        unchangedLock.Close();
        emptyLock.Close();
        //выводим первые строки после записи
        //первый файл не изменился
        Console.WriteLine("Unchanged: " + File.ReadLines("unchanged").FirstOrDefault());
        //второй стал пустым
        Console.WriteLine("Empty: " + File.ReadLines("empty").FirstOrDefault());
        //третий перезаписан, но не до конца
        Console.WriteLine("Partial: " + File.ReadLines("partial").FirstOrDefault());
        Console.Read();
    }
    static Thread CreateWriteThread(string filename)
    {
        var thread = new Thread(() =>
        {
            try
            {
                File.WriteAllLines(filename, Enumerable.Repeat("new line", 1000000));
            }
            catch{/*nobody cares*/}
        });
        thread.Start();
        return thread;
    }
}

Он выводит:

Unchanged: initial
Empty:
Partial: new line

Если нужна защита от ошибок при записи файла, т.е. чтобы было два варианта: либо файл записался полностью, либо не изменился, то попробуйте записать данные во временный файл, и поменять файлы местами. При этом все равно сохраняется возможность возникновения ошибок, но по крайней мере есть вариант для отката и исключается сценарий с частичной записью данных. Посмотрите How to do atomic writes in a file.

READ ALSO
Добавить в List<Object> экземпляр объекта

Добавить в List<Object> экземпляр объекта

Имеется один экземпляр Object, который каждый раз меняет свои значения свойств, при этом, после изменения свойства он добавляется в List через...

135
Как отобразить содержимое тега в HtmlDocument?

Как отобразить содержимое тега в HtmlDocument?

У меня проблема с парсингом HtmlDocument по какой то причине не могу войти в <td width="300px"> </td>

167
Как я могу заменить public GameObject из другого скрипта?

Как я могу заменить public GameObject из другого скрипта?

Как я могу заменить public GameObject из другого скрипта? Я должен сначала "найти скрипт" и потом передать ему другое значение или же есть более простой...

118
Как отловить зажатие клавиши Alt в событии MouseDown

Как отловить зажатие клавиши Alt в событии MouseDown

Имеется DataGrid (WinForms), в нем выводится список сущностейПри выборе сущности, в событии

188