使用 FileStream 保存图像有时会导致文件损坏

Saving an image using FileStream sometimes results in corrupt files

我有一个应用程序,我可以在其中拍照并按下保存按钮,然后将图像保存到计算机中。这在大多数情况下都可以正常工作。但是我看到我的一些用户有损坏的图像。这些图像的字节数大约是正确的,但是当尝试图像的字节数时,它只是一堆空值。

我保存照片的代码是:

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 Constructor (SafeFileHandle, FileAccess) 我读到这个:

When Close is called, the handle is also closed and the file's handle count is decremented.

FileStream assumes that it has exclusive control over the handle. Reading, writing, or seeking while a FileStream is also holding a handle could result in data corruption. For data safety, call Flush before using the handle, and avoid calling any methods other than Close after you are done using the handle.

但我不确定这是什么意思?我的用户是否可以在写入文件时让他们的平板电脑进入睡眠状态?发生这种情况还有什么其他原因?

要澄清 - 您需要致电 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,这将刷新中间文件缓冲区.