【问题标题】:Why can't this file be deleted after using C1ZipFile?为什么使用 C1ZipFile 后无法删除此文件?
【发布时间】:2009-07-06 15:51:57
【问题描述】:

以下代码给了我一个 System.IO.IOException 消息“进程无法访问文件”。

private void UnPackLegacyStats()
{
  DirectoryInfo oDirectory;
  XmlDocument oStatsXml;

  //Get the directory
  oDirectory = new DirectoryInfo(msLegacyStatZipsPath);

  //Check if the directory exists
  if (oDirectory.Exists)
  {
    //Loop files
    foreach (FileInfo oFile in oDirectory.GetFiles())
    {
      //Check if file is a zip file
      if (C1ZipFile.IsZipFile(oFile.FullName))
      {
        //Open the zip file
        using (C1ZipFile oZipFile = new C1ZipFile(oFile.FullName, false))
        {
          //Check if the zip contains the stats
          if (oZipFile.Entries.Contains("Stats.xml"))
          {
            //Get the stats as a stream
            using (Stream oStatsStream = oZipFile.Entries["Stats.xml"].OpenReader())
            {
              //Load the stats as xml
              oStatsXml = new XmlDocument();
              oStatsXml.Load(oStatsStream);

              //Close the stream
              oStatsStream.Close();
            }

            //Loop hit elements
            foreach (XmlElement oHitElement in oStatsXml.SelectNodes("/*/hits"))
            {
              //Do stuff
            }                
          }

          //Close the file
          oZipFile.Close();
        }
      }

      //Delete the file
      oFile.Delete();
    }
  }
}

我正在努力查看文件仍然可以锁定的位置。所有可能持有文件句柄的对象都在 using 块中并被显式关闭。

这与使用 FileInfo 对象而不是静态 GetFiles 方法返回的字符串有关吗?

有什么想法吗?

【问题讨论】:

  • 您究竟从哪里得到异常?

标签: c# .net file-io using


【解决方案1】:

我在您的代码中没有发现问题,一切看起来都还不错。要检查问题出在 C1ZipFile 我建议您从流初始化 zip,而不是从文件初始化,因此您明确关闭流:

//Open the zip file
using (Stream ZipStream = oFile.OpenRead())
using (C1ZipFile oZipFile = new C1ZipFile(ZipStream, false))
{
    // ...

其他几个建议:

  • 您不需要调用 Close() 方法,使用 (...),将它们删除。
  • 移动 xml 处理(循环命中元素)超大 zip 处理,即在 zip 文件关闭之后,因此您尽可能少地保持文件打开。

【讨论】:

  • 我现在对所有内容都使用流,而不是传递文件路径。这似乎解决了问题,尽管我认为是 IsZipFile() 调用持有文件而不是 zip 文件对象的锁。
【解决方案2】:

我假设您在调用 oFile.Delete 时遇到了错误。我能够重现此错误。有趣的是,该错误仅在文件不是 zip 文件时发生。这是您看到的行为吗?

当文件不是 zip 文件时,C1ZipFile.IsZipFile 调用似乎没有释放文件。我能够通过使用 FileStream 而不是将文件路径作为字符串传递(IsZipFile 函数接受任何一种)来避免这个问题。

因此,对您的代码进行以下修改似乎有效:

if (oDirectory.Exists)
{
    //Loop files
    foreach (FileInfo oFile in oDirectory.GetFiles())
    {
        using (FileStream oStream = new FileStream(oFile.FullName, FileMode.Open))
        {
            //Check if file is a zip file
            if (C1ZipFile.IsZipFile(oStream))
            {
            // ...
            }
        }
        //Delete the file
        oFile.Delete();
    }
}    

针对主题中的原始问题:我不知道是否可以知道是否可以在不尝试删除文件的情况下删除文件。您总是可以编写一个函数来尝试删除文件,如果不能,则捕获错误,然后返回一个布尔值,指示删除是否成功。

【讨论】:

  • 即使文件是 zip 文件,我的错误似乎也会发生,但使用流进行 IsZipFile 检查似乎已经解决了问题。我还使用流来打开 zip 文件,并且正在处理文件访问之外的 xml。
  • @Stevo,您需要将此问题发布到 ComponentOne。这绝对是个奇怪的错误。
  • @arbiter - 我会将它发布到 ComponentOne,我并不期望他们会对此做任何事情。我得出的结论是,很多 C1 组件都有这样的有趣问题。我一直想搬到 DotNetZip。
【解决方案3】:

我只是在猜测:你确定 oZipFile.Close() 就足够了吗?也许您必须调用 oZipFile.Dispose() 或 oZipFile.Finalize() 以确保它确实释放了资源。

【讨论】:

  • oZipFile 位于 using 块中,不公开这些方法中的任何一个。
【解决方案4】:

更可能它没有被处置,每当您访问托管代码(流、文件等)之外的东西时,您必须处置它们。我学会了使用 Asp.NET 和图像文件的艰难方法,它会填满你的内存,让你的服务器崩溃等等。

【讨论】:

    【解决方案5】:

    为了完整起见,我正在冒充我的工作代码,因为更改来自多个来源。

    private void UnPackLegacyStats()
    {
      DirectoryInfo oDirectory;
      XmlDocument oStatsXml;
    
      //Get the directory
      oDirectory = new DirectoryInfo(msLegacyStatZipsPath);
    
      //Check if the directory exists
      if (oDirectory.Exists)
      {
        //Loop files
        foreach (FileInfo oFile in oDirectory.GetFiles())
        {
          //Set empty xml
          oStatsXml = null;
    
          //Load file into a stream
          using (Stream oFileStream = oFile.OpenRead())
          {
            //Check if file is a zip file
            if (C1ZipFile.IsZipFile(oFileStream))
            {
              //Open the zip file
              using (C1ZipFile oZipFile = new C1ZipFile(oFileStream, false))
              {
                //Check if the zip contains the stats
                if (oZipFile.Entries.Contains("Stats.xml"))
                {
                  //Get the stats as a stream
                  using (Stream oStatsStream = oZipFile.Entries["Stats.xml"].OpenReader())
                  {
                    //Load the stats as xml
                    oStatsXml = new XmlDocument();
                    oStatsXml.Load(oStatsStream);
                  }
                }
              }
            }
          }
    
          //Check if we have stats
          if (oStatsXml != null)
          {
            //Process XML here
          }
    
          //Delete the file
          oFile.Delete();
        }
      }
    }
    

    我从中学到的主要教训是在调用代码的一个地方管理文件访问,而不是让其他组件管理自己的文件访问。当您想在其他组件完成任务后再次使用该文件时,这是最合适的。

    虽然这需要更多的代码,但您可以清楚地看到流的处理位置(在使用结束时),而不是必须相信组件已正确处理流。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-05
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 2018-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多