2009-07-06 20 views
3

次のコードは、 'プロセスはファイルにアクセスできません'というメッセージが表示されたSystem.IO.IOExceptionを返します。C1ZipFileを使用した後、このファイルを削除できないのはなぜですか?

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オブジェクトを使用することとは何か?

アイデア?

+0

どこで例外が発生していますか? –

+0

@Joshua - On oFile.Delete(); – stevehipwell

答えて

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

:それはファイルをしようとせずに削除することができるかどうかを知ることができるかどうかはわかりませんそれを削除する。ファイルを削除しようとする関数を書くことができ、できない場合はエラーをキャッチし、削除が成功したかどうかを示すブール値を返します。

+0

私のエラーは、ファイルがZIPファイルであっても発生するように見えましたが、IsZipFileチェックのストリームを使用すると問題が解決したようです。私はまた、zipファイルを開くためにストリームを使用しています、私はファイルアクセスの使用の外でxmlを処理しています。 – stevehipwell

+0

@Stevo、この問題をComponentOneに投稿する必要があります。これは間違いなく奇妙なバグです。 – arbiter

+0

@arbiter - 私はComponentOneに投稿しますが、私は彼らがそれについて何もしないという期待はしていません。私は、C1のコンポーネントの多くは、このような面白い問題があるという結論に達しました。私はDotNetZipに移動する意味を持っています。 – stevehipwell

1

私はちょうど推測です:oZipFile.Close()で十分ですか?おそらく、実際にリソースを解放したことを確認するために、oZipFile.Dispose()またはoZipFile.Finalize()を呼び出す必要があります。

+0

oZipFileはusingブロック内にあり、これらのメソッドのいずれも公開しません。 – stevehipwell

2

コードに問題はありません。すべてが正常に表示されます。確認するには問題は、私はあなたの代わりにファイルから初期化、ストリームからzipファイルを初期化する提案C1ZipFileに位置しているので、明示的に近いストリーム:

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

他のいくつかの提案:あなたはに

  • 必要はありません。 Close()メソッドを呼び出し、を使用して(...)を削除してください。
  • xml処理(ループヒット要素)のアウトサイズジップ処理(zipファイルの閉じ後)をできるだけ少なく開いたままにします。
+0

ファイルパスを渡さずにすべてのストリームを使用しています。これは問題を解決したようですが、Zipファイルオブジェクトではなくファイルへのロックを保持していたIsZipFile()呼び出しだと思います。 – stevehipwell

1

さらに処理されていない可能性があります。管理されたコード(ストリーム、ファイルなど)以外のものにアクセスするときはいつでも、それらを破棄しなければなりません。私はAsp.NETとImageファイルで難しい方法を学びました。メモリがいっぱいになり、サーバーがクラッシュしてしまいます。

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つの場所にあるファイルへのアクセスを管理することです。これは、他のコンポーネントがそのタスクを完了した後でファイルを再度使用する場合に最も適しています。

これはもう少しコードをとっていますが、コンポーネントがストリームを正しく廃棄していることを信頼する必要があるのに対して、ストリームがどこに配置されているのかを明確に確認できます。

関連する問題