我将PictureBox的图像指向某个文件“A”。在执行时我想将PictureBox的图像更改为另一个“B”但我收到以下错误:
“mscorlib.dll中出现'System.IO.IOException'类型的第一次机会异常 附加信息:进程无法访问文件“A”,因为它正由另一个进程使用。“
我按如下方式设置图像:
pbAvatar.Image = new Bitmap(filePath);
如何解锁第一个文件?
答案 0 :(得分:49)
这是我打开图像而不锁定文件的方法......
public static Image FromFile(string path)
{
var bytes = File.ReadAllBytes(path);
var ms = new MemoryStream(bytes);
var img = Image.FromStream(ms);
return img;
}
更新:我做了一些性能测试,看看哪种方法最快。我将它与@net_progs“从位图复制”答案(这似乎是最接近正确的,但确实有一些问题)进行了比较。我为每种方法加载了10000次图像并计算了每张图像的平均时间。结果如下:
Loading from bytes: ~0.26 ms per image.
Copying from bitmap: ~0.50 ms per image.
结果似乎有意义,因为您必须使用位图方法的副本创建图像两次。
更新: 如果你需要BitMap,你可以这样做:
return (Bitmap)Image.FromStream(ms);
答案 1 :(得分:38)
这是一个在网络上广泛讨论的常见锁定问题。
使用流建议的技巧不起作用,实际上它最初有效,但稍后会导致问题。例如,它将加载图像并且文件将保持解锁状态,但如果您尝试通过Save()方法保存加载的图像,它将抛出一个通用的GDI +异常。
接下来,每像素复制的方式似乎并不牢固,至少它是嘈杂的。
我发现的工作原理如下:http://www.eggheadcafe.com/microsoft/Csharp/35017279/imagefromfile--locks-file.aspx
这是图像的加载方式:
Image img;
using (var bmpTemp = new Bitmap("image_file_path"))
{
img = new Bitmap(bmpTemp);
}
我一直在寻找这个问题的解决方案,这个方法到目前为止对我来说还不错,所以我决定对它进行描述,因为我发现有很多人在网上和网上都提出错误的流方法。
答案 2 :(得分:25)
使用文件流会在文件被读取并处理后解锁文件:
using (var fs = new System.IO.FileStream("c:\\path to file.bmp", System.IO.FileMode.Open))
{
var bmp = new Bitmap(fs);
pct.Image = (Bitmap) bmp.Clone();
}
编辑更新以允许处理原始位图,并允许关闭FileStream。
此答案不安全 - 请参阅评论,并参阅net_prog's answer中的讨论。编辑以使用Clone
并不会使其更安全 - 克隆克隆所有字段,包括文件流引用,在某些情况下会导致问题。
答案 3 :(得分:5)
当位图对象仍在使用它时,您无法处置/关闭流。 (如果你知道你正在使用什么类型的文件以及你将要执行什么操作,那么位图对象是否需要再次访问它只是确定性的 - 例如对于SOME .gif格式图像,流之前关闭构造函数返回。)
Clone创建位图的“精确副本”(每个文档; ILSpy显示它调用本机方法,因此现在跟踪太多了)可能,它也会复制Stream数据 - 否则它就不会'是一个精确的副本。
您最好的选择是创建像素完美的图像副本 - 尽管YMMV(某些类型的图像可能有多个帧,或者您可能还需要复制调色板数据。)但对于大多数图像,这有效:
static Bitmap LoadImage(Stream stream)
{
Bitmap retval = null;
using (Bitmap b = new Bitmap(stream))
{
retval = new Bitmap(b.Width, b.Height, b.PixelFormat);
using (Graphics g = Graphics.FromImage(retval))
{
g.DrawImage(b, Point.Empty);
g.Flush();
}
}
return retval;
}
然后你可以像这样调用它:
using (Stream s = ...)
{
Bitmap x = LoadImage(s);
}
答案 4 :(得分:4)
这是我目前使用的技术,似乎效果最好。它的优点是可以生成具有相同像素格式(24位或32位)和分辨率(72 dpi,96 dpi等)的Bitmap对象作为源文件。
// ImageConverter object used to convert JPEG byte arrays into Image objects. This is static
// and only gets instantiated once.
private static readonly ImageConverter _imageConverter = new ImageConverter();
这可以根据需要经常使用,如下所示:
Bitmap newBitmap = (Bitmap)_imageConverter.ConvertFrom(File.ReadAllBytes(fileName));
编辑: 以下是上述技术的更新:https://stackoverflow.com/a/16576471/253938
答案 5 :(得分:3)
(The accepted answer错误。当你在克隆位图上尝试LockBits(...)
时,最终会遇到GDI +错误。)
new Bitmap(temp_filename)
Clone()
)并处理第一个位图答案 6 :(得分:1)
据我所知,这是100%安全的,因为生成的图像是100%在内存中创建的,没有任何链接资源,并且在内存中没有留下开放流。它的行为与从没有指定任何输入源的构造函数创建的任何其他Bitmap
一样,与此处的其他一些答案不同,它保留了原始像素格式,这意味着它可以是用于索引格式。
基于this answer,但有额外的修复,没有外部库导入。
/// <summary>
/// Clones an image object to free it from any backing resources.
/// Code taken from http://stackoverflow.com/a/3661892/ with some extra fixes.
/// </summary>
/// <param name="sourceImage">The image to clone</param>
/// <returns>The cloned image</returns>
public static Bitmap CloneImage(Bitmap sourceImage)
{
Rectangle rect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
Bitmap targetImage = new Bitmap(rect.Width, rect.Height, sourceImage.PixelFormat);
targetImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
BitmapData sourceData = sourceImage.LockBits(rect, ImageLockMode.ReadOnly, sourceImage.PixelFormat);
BitmapData targetData = targetImage.LockBits(rect, ImageLockMode.WriteOnly, targetImage.PixelFormat);
Int32 actualDataWidth = ((Image.GetPixelFormatSize(sourceImage.PixelFormat) * rect.Width) + 7) / 8;
Int32 h = sourceImage.Height;
Int32 origStride = sourceData.Stride;
Boolean isFlipped = origStride < 0;
origStride = Math.Abs(origStride); // Fix for negative stride in BMP format.
Int32 targetStride = targetData.Stride;
Byte[] imageData = new Byte[actualDataWidth];
IntPtr sourcePos = sourceData.Scan0;
IntPtr destPos = targetData.Scan0;
// Copy line by line, skipping by stride but copying actual data width
for (Int32 y = 0; y < h; y++)
{
Marshal.Copy(sourcePos, imageData, 0, actualDataWidth);
Marshal.Copy(imageData, 0, destPos, actualDataWidth);
sourcePos = new IntPtr(sourcePos.ToInt64() + origStride);
destPos = new IntPtr(destPos.ToInt64() + targetStride);
}
targetImage.UnlockBits(targetData);
sourceImage.UnlockBits(sourceData);
// Fix for negative stride on BMP format.
if (isFlipped)
targetImage.RotateFlip(RotateFlipType.Rotate180FlipX);
// For indexed images, restore the palette. This is not linking to a referenced
// object in the original image; the getter of Palette creates a new object when called.
if ((sourceImage.PixelFormat & PixelFormat.Indexed) != 0)
targetImage.Palette = sourceImage.Palette;
// Restore DPI settings
targetImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
return targetImage;
}
要打电话,只需使用:
/// <summary>Loads an image without locking the underlying file.</summary>
/// <param name="path">Path of the image to load</param>
/// <returns>The image</returns>
public static Bitmap LoadImageSafe(String path)
{
using (Bitmap sourceImage = new Bitmap(path))
{
return CloneImage(sourceImage);
}
}
或者,从字节:
/// <summary>Loads an image from bytes without leaving open a MemoryStream.</summary>
/// <param name="fileData">Byte array containing the image to load.</param>
/// <returns>The image</returns>
public static Bitmap LoadImageSafe(Byte[] fileData)
{
using (MemoryStream stream = new MemoryStream(fileData))
using (Bitmap sourceImage = new Bitmap(stream)) {
{
return CloneImage(sourceImage);
}
}
答案 7 :(得分:0)
将其读入流中,创建位图,关闭流。
答案 8 :(得分:0)
我建议使用 PixelMap (在NuGet上可用) 或Github
非常好用,比.NET中的标准位图要快
download(user) {
this.clientAPI.get(Endpoints.DOWNLOAD).toPromise()
.then(res => {
let blob = new Blob([new Uint8Array(res.file)], { type: 'application/zip' });
console.log('blob',blob);
let a = document.createElement('a');
a.href = (URL.createObjectURL(blob));
a.download = res.filename;
document.body.appendChild(a);
a.click();
a.remove();
// this.downloadComplete(user);
})
.catch(err => console.error("download error = ", err))
}
Here is my backend code (Node Js):-
exports.download = function (req, res) {
let file = process.env.NOCE_ENV === 'local' ? `${process.cwd()}/server/downloads/eFAST-Release-20.5.17.19.zip` :
`${process.cwd()}/server/downloads/eFAST-Release-20.5.17.19.zip`;
let filename = path.basename(file);
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type', "application/zip");
let filestream = fs.createReadStream(file);
// console.log('filestream',filenter code hereestream)
res.jsonp({ filename: filename, file: filestream });
};
答案 9 :(得分:-2)
三年前,我写了一个图片浏览器程序,看看能否做到。上周,我添加了扫描图像的代码。 (我计划在收到错误后将其添加到家谱程序中。) 要裁剪未使用的区域,我正在使用文件名调用MSPaint程序。我在那里编辑然后保存。当我关闭Paint时,图像会显示更改 如果我对图像做了任何事情,我在Paint中收到关于文件被锁定的错误。我使用Image,FromStream()更改程序以锁定图像。我不再在Paint中获得该消息。 (我的程序是在VB 2010中。)