Почему этот файл нельзя удалить после использования C1ZipFile?

StackOverflow https://stackoverflow.com/questions/1087746

  •  23-08-2019
  •  | 
  •  

Вопрос

Следующий код выдает исключение 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?

Есть идеи?

Это было полезно?

Решение

Я предполагаю, что вы получаете ошибку при вызове oFile.Delete.Мне удалось воспроизвести эту ошибку.Интересно, что ошибка возникает только тогда, когда файл нет zip-файл.Это то поведение, которое вы наблюдаете?

Похоже, что вызов C1ZipFile.IsZipFile не освобождает файл, если он не является zip-файлом.Мне удалось избежать этой проблемы, используя 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();
    }
}    

В ответ на исходный вопрос в теме:Я не знаю, можно ли узнать, можно ли удалить файл, не пытаясь его удалить.Вы всегда можете написать функцию, которая пытается удалить файл и обнаруживает ошибку, если это не удается, а затем возвращает логическое значение, указывающее, было ли удаление успешным.

Другие советы

Я не вижу проблем в вашем коде, все в порядке.Чтобы проверить, заключается ли проблема в C1ZipFile, я предлагаю вам инициализировать zip из потока вместо инициализации из файла, поэтому вы явно закрываете поток:

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

Несколько других предложений:

  • Вам не нужно вызывать метод Close(), т.к. с использованием (...), удалить их.
  • Переместить обработку XML (элементы циклического попадания) за пределы обработки zip, т.е.после закрытия zip-файла, чтобы файл оставался открытым как можно реже.

Я просто предполагаю:вы уверены, что oZipFile.Close() достаточно?Возможно, вам придется вызвать oZipFile.Dispose() или oZipFile.Finalize(), чтобы убедиться, что ресурсы действительно освобождены.

Более того, скорее всего, он не удаляется, каждый раз, когда вы получаете доступ к чему-то за пределами управляемого кода (потоки, файлы и т. д.), вы ДОЛЖНЫ избавиться от них.Я на собственном горьком опыте научился работе с файлами Asp.NET и изображения: это заполнит вашу память, приведет к сбою вашего сервера и т. д.

Для полноты картины я представляю свой рабочий код, поскольку изменения произошли из более чем одного источника.

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

Главный урок, который я извлек из этого, — управлять доступом к файлам в одном месте вызывающего кода, а не позволять другим компонентам управлять собственным доступом к файлам.Это наиболее удобно, если вы хотите снова использовать файл после того, как другой компонент завершил свою задачу.

Хотя для этого требуется немного больше кода, вы можете четко видеть, где расположен поток (в конце использования), по сравнению с необходимостью полагаться на то, что компонент правильно удалил поток.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top