使用C1ZipFile后为什么不能删除此文件?

时间:2009-07-06 15:51:57

标签: c# .net file-io using

以下代码为我提供了一个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();
    }
  }
}

我正在努力查看文件仍然可以锁定的位置。可以保留在文件句柄上的所有对象都在使用块并显式关闭。

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

有什么想法吗?

5 个答案:

答案 0 :(得分:2)

我没有看到代码中的问题,一切看起来都不错。要检查问题在于C1ZipFile我建议你从流初始化zip,而不是从文件初始化,所以你明确地关闭流:

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

其他一些建议:

  • 您无需调用Close()方法,使用使用(...),将其删除。
  • 移动xml处理(循环命中元素)超大了zip处理,即在zip文件关闭后,所以你尽可能地保持文件打开。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

我假设您在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();
    }
}    

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

答案 3 :(得分:1)

更多可能它没有被处理,只要你访问托管代码之外的东西(流,文件等),你必须处理它们。我用Asp.NET和Image文件学到了很多东西,它会填满你的内存,崩溃你的服务器等等。

答案 4 :(得分:1)

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

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();
    }
  }
}

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

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