我正在使用此代码创建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);
}
完成后,我调用一个函数来删除Images Folder。"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秒的时间,直到"那个东西"释放图像,应用程序能够删除文件夹,而整个应用程序被冻结哪行代码保存图像(图像)
与其使用Image.FromFile
获取图像,不如使用流读取图像的副本,然后使用此副本进行操作。Image.FromFile
的问题是,它通过引用打开您的图像文件,这样在应用程序停止使用它之前,任何其他操作都无法对其进行写入。它基本上是一个永远不会关闭的流,直到它完全超出范围或手动.Dispose()
图像对象。
所以,更改这一行:
var ImageToPutInReport = Image.FromFile(imagePath);
到此行:
Image ImageToPutInReport;
using (FileStream stream = File.OpenRead(imagePath))
{
ImageToPutInReport = Image.FromStream(stream);
}
从Image.FromFile(string filename)
上的这个链接中,它显示The file remains locked until the Image is disposed.
,并且您不会在任何地方偶极化图像。
这就是造成你问题的原因。
此行:
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行为。
附言:正如我上面提到的,正如@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();