浮动布局面板填充图片时遇“图片被其他进程占用”问题求助
解决“picture is used by another process”错误的方案
你碰到的这个问题其实很常见——Image.FromFile()方法有个容易踩的坑:它会一直持有图片文件的独占锁,直到对应的Image对象被垃圾回收。这就导致当你的布局面板或者其他代码试图访问同一张图片文件时,会因为文件被当前进程占用而抛出那个“被另一个进程使用”的异常。
给你两个靠谱的解决方案,选一个适合你的场景就行:
方案1:用FileStream加载并及时释放句柄
替换原来直接用Image.FromFile()的代码,改用FileStream来读取文件,利用using块自动释放流资源,这样文件锁会被及时解除:
private void FillPanel(string sql) { // 先释放旧控件的图片资源,避免内存泄漏 foreach (Control ctrl in panel.Controls) { if (ctrl is PictureBox pb) { pb.Image?.Dispose(); } } panel.Controls.Clear(); SQLiteConnection dbConnect = new SQLiteConnection("Data Source=" + dbFullPath + ";Version=3;"); dbConnect.Open(); SQLiteCommand runQuery = new SQLiteCommand(sql, dbConnect); SQLiteDataReader reader = runQuery.ExecuteReader(); while (reader.Read()) { PictureBox pB = new PictureBox(); string imgPath = reader["imgPath"].ToString(); // 用FileStream加载图片 using (FileStream fs = new FileStream(imgPath, FileMode.Open, FileAccess.Read)) { pB.Image = Image.FromStream(fs); } pB.Size = new Size(100, 100); // 这里补充你原来的其他设置,比如pB.SizeMode之类的 panel.Controls.Add(pB); } // 记得释放数据库资源 reader.Close(); dbConnect.Close(); }
说明:using块会在代码执行完后自动关闭并释放FileStream,此时文件锁会被解除。Image.FromStream()会把图片内容读取到内存中,所以关闭流后图片依然可以正常显示。
方案2:把图片加载到内存流(彻底脱离文件依赖)
如果你的场景需要频繁操作图片文件,或者担心流的生命周期问题,可以把图片文件全部读到内存流里,再基于内存流创建Image:
// 替换加载图片的那段代码 string imgPath = reader["imgPath"].ToString(); byte[] imgBytes = File.ReadAllBytes(imgPath); using (MemoryStream ms = new MemoryStream(imgBytes)) { pB.Image = Image.FromStream(ms); }
说明:这种方式把图片内容完全加载到内存中,和原文件彻底脱离关系,自然不会产生文件锁定问题,适合需要对原文件进行修改、删除等操作的场景。
另外还要注意:每次调用panel.Controls.Clear()之前,一定要先遍历所有PictureBox并调用Image.Dispose(),否则会造成内存泄漏——因为Image对象是包含非托管资源的,不会被自动回收。
内容的提问来源于stack exchange,提问作者Arimatas
相关产品推荐
相关产品推荐

