Сохранение изображения с помощью FileStream иногда приводит к повреждению файлов
У меня есть приложение, где я делаю снимок, нажимаю кнопку сохранения и сохраняю изображение на компьютере. Это прекрасно работает большую часть времени. Но я вижу некоторых из моих пользователей с поврежденными изображениями. Эти изображения имеют правильное количество байтов по размеру, но при попытке использовать байты для изображения это просто загрузка нулевых значений.
Мой код для сохранения фотографий:
try
{
using (FileStream stream = new FileStream(localCopyFileLocation, FileMode.Create))
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.QualityLevel = quality;
encoder.Frames.Add(BitmapFrame.Create(photo, null, metadata, null));
encoder.Save(stream);
}
}
catch (Exception ex)
{
//Write to log etc.
}
Из конструктора FileStream (SafeFileHandle, FileAccess) я прочитал это:
Когда вызывается метод Close, дескриптор также закрывается, и количество дескрипторов файла уменьшается.
FileStream предполагает, что он имеет исключительный контроль над дескриптором. Чтение, запись или поиск, когда FileStream также содержит дескриптор, может привести к повреждению данных. Для безопасности данных, вызовите Flush перед использованием дескриптора и избегайте вызова любых методов, кроме Close, после того как вы покончили с использованием дескриптора.
Но я не уверен, что это значит? Могут ли мои пользователи усыплять свои планшеты во время записи файла? Какие еще причины могут быть, что это происходит?
1 ответ
Чтобы уточнить - нужно позвонить Flush()
,
призвание Close()
недостаточно. Close()
звонки Dispose()
который делает следующее
protected override void Dispose(bool disposing)
{
try
{
if (this._handle != null && !this._handle.IsClosed && this._writePos > 0)
{
this.FlushWrite(!disposing);
}
}
finally
{
if (this._handle != null && !this._handle.IsClosed)
{
this._handle.Dispose();
}
this._canRead = false;
this._canWrite = false;
this._canSeek = false;
base.Dispose(disposing);
}
}
С другой стороны, вот что Flush()
делает:
public override void Flush()
{
this.Flush(false);
}
Какие звонки:
public virtual void Flush(bool flushToDisk)
{
if (this._handle.IsClosed)
{
__Error.FileNotOpen();
}
this.FlushInternalBuffer();
if (flushToDisk && this.CanWrite)
{
this.FlushOSBuffer();
}
}
Ключ (я думаю, но я не уверен) FlushOSBuffer()
private void FlushOSBuffer()
{
if (!Win32Native.FlushFileBuffers(this._handle))
{
__Error.WinIOError();
}
}
Если звонит Flush()
не работает, чем попробовать переопределить Flush(true)
что приведет к вызову Win32 API FlushFileBuffers, который очистит промежуточные файловые буферы.