3

次のコードは、「プロセスはファイルにアクセスできません」というメッセージとともに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();
    }
  }
}

ファイルがまだロックされている可能性がある場所を確認するのに苦労しています。ファイルへのハンドルを保持している可能性のあるすべてのオブジェクトは、ブロックを使用しており、明示的に閉じられています。

静的なGetFilesメソッドによって返される文字列ではなく、FileInfoオブジェクトを使用することと関係がありますか?

何か案は?

4

5 に答える 5

2

コードに問題はありません。すべて問題ないようです。問題がC1ZipFileにあるかどうかを確認するには、ファイルからの初期化ではなく、ストリームからzipを初期化することをお勧めします。そのため、ストリームを明示的に閉じます。

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

他のいくつかの提案:

  • (...)を使用してClose()メソッドを呼び出す必要はなく、それらを削除します。
  • xml処理(ループヒット要素)をzip処理よりも大きくします。つまり、zipファイルを閉じた後、ファイルをできるだけ開いたままにします。
于 2009-07-06T18:35:53.547 に答える
1

推測しているだけです。oZipFile.Close()で十分ですか?おそらく、oZipFile.Dispose()またはoZipFile.Finalize()を呼び出して、実際にリソースが解放されていることを確認する必要があります。

于 2009-07-06T16:10:16.630 に答える
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();
    }
}    

件名の元の質問への回答:ファイルを削除しようとせずにファイルを削除できるかどうかを知ることができるかどうかはわかりません。ファイルを削除しようとし、それができない場合はエラーをキャッチし、削除が成功したかどうかを示すブール値を返す関数をいつでも作成できます。

于 2009-07-06T19:25:09.093 に答える
1

さらに、おそらくそれは破棄されていません。マネージコードの外部(ストリーム、ファイルなど)にアクセスするときはいつでも、それらを破棄する必要があります。Asp.NETファイルと画像ファイルで難しい方法を学びました。メモリがいっぱいになったり、サーバーがクラッシュしたりします。

于 2009-07-06T20:04:24.397 に答える
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();
    }
  }
}

これから学んだ主な教訓は、他のコンポーネントに独自のファイルアクセスを管理させるのではなく、呼び出し元のコードの1か所でファイルアクセスを管理することです。これは、他のコンポーネントがタスクを終了した後でファイルを再度使用する場合に最も適しています。

これにはもう少しコードが必要ですが、コンポーネントがストリームを正しく破棄したことを信頼する必要がある場合と比較して、ストリームがどこに破棄されるか(使用の最後)を明確に確認できます。

于 2009-07-07T08:32:54.377 に答える