Как обеспечить, чтобы все данные были физически записаны на диск? - PullRequest
18 голосов
/ 20 декабря 2008

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

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

Ответы [ 6 ]

15 голосов
/ 22 октября 2010

Стефан С. сказал:

Я понимаю, что метод Flush .NET FileStream записывает только текущий буфер на диск

Нет, .NET FileStream's Flush только записывает буферы .NET в кеш ОС, но не сбрасывает кеш ОС на диск. К сожалению, документ MSDN этого класса не говорит этого. Для .NET <4.0 вам нужно вызвать FlushFilebuffers Flush + Win32: </p>

using System.Runtime.InteropServices;
. . .

// start of class:
[DllImport("kernel32", SetLastError=true)]
private static extern bool FlushFileBuffers(IntPtr handle);
. . .

stream.Flush();     // Flush .NET buffers to OS file cache.
#pragma warning disable 618,612 // disable stream.Handle deprecation warning.
if (!FlushFileBuffers(stream.Handle))   // Flush OS file cache to disk.
#pragma warning restore 618,612
{
  Int32 err = Marshal.GetLastWin32Error();
  throw new Win32Exception(err, "Win32 FlushFileBuffers returned error for " + stream.Name);
}

Для .NET 4.0 вы можете вместо этого использовать новый метод flush (true). 11/09/2012 обновление: отчет об ошибках MS здесь говорит, что он сломан, затем исправлен, но не говорит, в какой версии или в пакете обновления он был исправлен! Похоже, ошибка была, если внутренний буфер .NET FileStream пуст, Flush (true) ничего не сделал ??

8 голосов
/ 20 декабря 2008

В Windows посмотрите FlushFileBuffers (Win32 API).

3 голосов
/ 19 мая 2012

Я заметил, что .NET 4 #Flush (true) фактически не записывает на диск. У нас были странные проблемы с поврежденными данными, и я нашел это сообщение об ошибке на сайте MS:

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

  1. Запись данных на диск
  2. fs.Flush(true). Это не займет много времени (намного быстрее, чем возможно записать на диск).
  3. Используйте win32 API FlushFileBuffers. Это занимает много времени.

Я перехожу на вызов Win32 FlushFileBuffers ...

3 голосов
/ 20 декабря 2008

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

Транзакционная файловая система так и не материализовалась ;-p Конечно, вы могли бы рассмотреть использование базы данных в качестве бэк-энда и использовать систему транзакций этого?

В сторону: обратите внимание, что не все потоки даже гарантируют Flush() - например, GZipStream и т. Д. Сохраняют рабочий буфер незафиксированных данных даже после сброса - единственный способ заставить его сбросить все это Close() это.

0 голосов
/ 21 сентября 2016

Данные файла, которые буферизируются в кеше файловой системы для записи на диск. Эти данные обычно записываются лениво, в зависимости от положения головки записи на диск. Технически возможно иметь гигабайт кэшированных данных, поэтому это может занять довольно много времени. Если это важно для вас, рассмотрите вариант FileOptions.WriteThrough.

0 голосов
/ 20 декабря 2008

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

Не блестяще работает и не защищен от ошибок, но как насчет повторного открытия файла после его записи в отдельном процессе и проверки размера или содержимого?

...