Сохранение изображения с помощью 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, который очистит промежуточные файловые буферы.

Другие вопросы по тегам