我正在使用此代码创建Excel文件并使用数据填充它:
using (ExcelPackage package = new ExcelPackage(fileInfo))
{
ExcelWorksheet ws = package.Workbook.Worksheets.Add("Deltas");
ExcelWorksheet ws2 = package.Workbook.Worksheets.Add("Images");
ExcelWorksheet ws3 = package.Workbook.Worksheets.Add("Data Points");
GenerateDataSheet(ws, true);
GenerateDataSheet(ws3, false);
// populate second worksheet with images
var imagesLocations = SelectedSession.GetTests().Where(t => t.IsReference).Select(t => t.Location).OrderBy(t => t.DateCreated).ThenBy(t => t.Name).ToList();
ws2.Column(2).Width = 58;
for (int i = 0; i < imagesLocations.Count; i++)
{
ws2.Row(i + 1).Height = 305;
ws2.Cells[i + 1, 1].Value = imagesLocations[i].Name;
ws2.Cells[i + 1, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Top;
ws2.Cells[i + 1, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
var imagePath = imagesLocations[i].Tests.FirstOrDefault(t => t.IsReference).ImagePath;
if (File.Exists(imagePath))
{
var ImageToPutInReport = Image.FromFile(imagePath);
var image = ws2.Drawings.AddPicture(imagesLocations[i].Name, ImageToPutInReport);
image.SetSize(375, 375);
image.SetPosition(i, 0, 1, 0);
}
}
package.SaveAs(fileInfo);
}
完成后,我调用一个函数来删除图像文件夹。 “delete()”函数弹出错误:
图片仍在使用中
当我评论上述代码时,不会发生错误。目前我正在使用这个黑客来解决我的问题:
public static void DeleteSessionFolder(string session)
{
try
{
if (Directory.Exists(baseSessionPath + session))
Directory.Delete(baseSessionPath + session, true); // error pops here
} catch (Exception e)
{
DeleteSessionFolder(session); // call it again
}
}
所以我有机会一次又一次地尝试。但是这需要15秒,直到“那件事”发布图像并且应用程序能够删除文件夹,而整个应用程序被冻结。 哪一行代码保留图像(图像)?
答案 0 :(得分:4)
您应该使用流来读取图像副本,然后使用此副本进行操作,而不是使用Image.FromFile
来获取图像。 Image.FromFile
的问题在于它通过引用打开您的图像文件,以便在您的应用程序停止使用它之前,其他任何操作都无法写入。它基本上是一个永不关闭的流,直到完全超出范围或您手动.Dispose()
图像对象。
所以,改变这一行:
var ImageToPutInReport = Image.FromFile(imagePath);
到这一行:
Image ImageToPutInReport;
using (FileStream stream = File.OpenRead(imagePath))
{
ImageToPutInReport = Image.FromStream(stream);
}
答案 1 :(得分:1)
Image.FromFile(string filename)
上的this链接显示The file remains locked until the Image is disposed.
并且您不会将图片放在任何位置。
这就是造成你问题的原因。
答案 2 :(得分:1)
这一行:
var ImageToPutInReport = Image.FromFile(imagePath);
保持你的图像被打开并锁定,直到你处理掉它(因为你没有明确地做,直到垃圾收集器决定发生这种情况:那些应该是你在重试时观察的15秒)。 ..所以我将该块更改为:
using(var ImageToPutInReport = Image.FromFile(imagePath))
{
var image = ws2.Drawings.AddPicture(imagesLocations[i].Name, ImageToPutInReport);
image.SetSize(375, 375);
image.SetPosition(i, 0, 1, 0);
}
您需要确保将Image
对象复制(并且未链接)到电子表格中,否则,您需要稍后处理它们,但应该就是这样,采取你所看到的GC行为。
PS:正如我上面提到的,并且正如@ScottChamberlain在评论中指出的那样,图像可能会被添加为参考(而不是副本),因此您需要处置集合中引用的图像。 如果是这种情况,我们可以通过创建副本来解锁文件(这应该释放文件),然后在我们完成我们的软件包之后再处理副本......像:
var imageList = new List<Image>();
using (ExcelPackage package = new ExcelPackage(fileInfo))
{
/* ... */
if (File.Exists(imagePath))
{
Image ImageToPutInReport;
// Make a copy of the loaded image and dispose the original
// so the file is freed
using(var tempImage = Image.FromFile(imagePath))
ImageToPutInReport = new Bitmap(tempImage);
// Add to the list of images we'll dispose later
// after we're done
imageList.Add(ImageToPutInReport);
var image = ws2.Drawings.AddPicture(imagesLocations[i].Name, ImageToPutInReport);
image.SetSize(375, 375);
image.SetPosition(i, 0, 1, 0);
}
/* ... */
package.SaveAs(fileInfo);
}
foreach(var img in imageList)
img.Dispose();
imageList.Clear();