在WPF中加载BitmapSource并使用相同的名称保存 -> IOException

5

当我尝试保存之前加载的位图源(BitmapSource)时,会抛出 System.IO.IOException,指出另一个进程正在访问该文件,因此无法打开文件流。

如果只进行保存操作而没有进行加载操作,则一切正常。

加载代码如下:

BitmapImage image = new BitmapImage();

image.BeginInit();
image.UriSource = uri;

if (decodePixelWidth > 0)
image.DecodePixelWidth = decodePixelWidth;

image.EndInit();

代码的保存:

using (FileStream fileStream = new FileStream(Directory + "\\" + FileName + ".jpg", FileMode.Create))
{
    JpegBitmapEncoder encoder = new JpegBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create((BitmapImage)image));
    encoder.QualityLevel = 100;
    encoder.Save(fileStream);
}

看起来在加载图像数据后,只要打开它的应用程序仍在运行,该文件就会被锁定,无法被覆盖。有什么解决办法吗?非常感谢任何解决方案。

5个回答

9

受到此问题评论的启发,我通过将所有字节读入内存流并将其用作BitmapImage的Sreamsource来解决了问题。

这个方法完美地解决了问题:

if (File.Exists(filePath))
{
    MemoryStream memoryStream = new MemoryStream();

    byte[] fileBytes = File.ReadAllBytes(filePath);
    memoryStream.Write(fileBytes, 0, fileBytes.Length);
    memoryStream.Position = 0;

    image.BeginInit();
    image.StreamSource = memoryStream;

    if (decodePixelWidth > 0)
        image.DecodePixelWidth = decodePixelWidth;

    image.EndInit();
}

你拿了别人的评论,没有给任何人点赞,创造了一个派生解决方案并将其发布为答案,然后你给自己投了“海报批准答案”的票? - hughdbrown
15
我是StackOverflow的新手,如您所见。因此,在我的声望达到15之前,我就不能给别人点赞。由于其他人提供了很好的建议,但并没有为遇到相同问题的人提供真正的解决方案,所以我通过自己的研究得出了答案。有问题吗? - sdippl

7

这是另一种解决方案,基于原始的加载代码:

var image = new BitmapImage();
image.BeginInit();

// overwrite cache if already exists, to refresh image
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
// load into memory and unlock file
image.CacheOption = BitmapCacheOption.OnLoad;

image.UriSource = uri;
if (decodePixelWidth > 0) image.DecodePixelWidth = decodePixelWidth;
image.EndInit();

3
请将以下一行代码添加到您的加载代码中:
image.CacheOption = BitmapCacheOption.OnLoad;

这将在image.EndInit期间加载打开文件,将其读入内存并关闭。使用BitmapCacheOption.Default的默认行为是打开文件,将其读入内存,但在image.EndInit之前不会关闭。


1
这个可以工作,但是如果你在进程中稍后创建了一个使用相同路径的新的BitmapImage时,你还需要使用BitmapCreateOptions.IgnoreImageCache。这是因为BitmapImage将在BitmapImage类的实例之间缓存图像数据。 - reustmd
@manu08:如果我能以某种方式为此点赞就好了。我花了很长时间四处寻找,但找不到解决我的问题的方法。在写自己的SO问题时,我很幸运地发现了你的评论,而它正是我所需要的! - Dave

0

现在我不确定这是否适用于BitmapImage,但我曾经在GDI+中保存修改后的图像到原始文件时遇到过非常类似的问题here

从文件加载图像的方法会保持文件上的锁定,直到图像对象被处理。

也许BitmapImage.urisource也是同样的情况。不妨将图像复制到内存中并处理原始图像以解除文件锁定?


0
将CacheOption设置为BitmapCacheOption.OnLoad并不能解决你的问题。我认为这可能是一个bug,因为我也遇到了同样的问题。最终,我将图像加载到内存流中,在保存图像到文件之前释放了BitmapImage。

实际上,这对我来说完全正常。您必须创建BitmapImage,调用BeginInit(),然后设置CacheOption,然后设置UriSource,最后调用EndInit()。 - Caleb Vear

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接