哪一行代码仍在使用该文件而没有释放它

  • 本文关键字:文件 释放 一行 代码 c# excel
  • 更新时间 :
  • 英文 :


我正在使用此代码创建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();

最新更新