ZIP ファイル

Last Updated 2011/09/21


.NET Framework にはファイルを圧縮・解凍する機能を提供する GZipStream クラスはありますが、これは標準的に使われている ZIP 形式のファイルを扱うことはできません。このページでは C#(または Visual Basic)で ZIP ファイルを作成または展開する手順について説明します。


ファイルを圧縮・解凍するアルゴリズムとして、日本では日本で開発された LHA 形式が多く使われていますが、世界標準は ZIP 形式です。しかし、.NET Framework は ZIP を扱うことができません。XPS ドキュメントをパッケージ化するための ZipPackage クラスが ZIP 形式を使っているにもかかわらずです。XPS は国際的な規格ですから、.NET Framework でしか使えない形式を採用することはできなかったためと想像します。

LHA 形式の場合、無料で公開されている UNLHA32.DLL を使うことができます。同様に、ZIP 形式に対応したライブラリが公開されていますので、紹介します。 以下にサイトに入ってください。サイト名は、SharpZipLib です。

http://sharpziplib.com/

このページの [Download the Most Current Build] に入って、[Available downloads] の 3 つのファイルをダウンロードしてください。

目的のライブラリは ICSharpCode.SharpZipLib.dll です。

英文のヘルプは付いていますが、フリーウエアソフトにありがちな手抜きヘルプですね。そこで、ライブラリの検証のついでにマニュアルを作成しました。HTML 形式のヘルプです。

ICSharpCode.SharpZipLib.dll は ZIP 形式だけでなく、TAR 形式なども扱えますが、私自身は興味がないので、このマニュアルは ZIP 形式だけを取り上げました。テストしたところ、圧縮も解凍も正常に動作しますし、必要と思われる機能はすべて備えているといっていいと思います。

SharpZip.zip (127,241 bytes)

ICSharpCode.SharpZipLib.dll の使い方

ZIP 形式でファイルを圧縮・解凍するには FastZip クラスを使う手が簡単です。クラス名を見てすぐに想像できるように、簡易的な方法を提供するクラスですが、必要かつ十分な機能を持っています。このクラスの CreateZip メソッドは指定のディレクトリに含まれるファイル(ディレクトリを含むことも可能)を圧縮し、ZIP ファイルを作成します。また、ExtractZip メソッドは指定の ZIP ファイルを解凍します。

ライブラリに含まれるクラスの解説は、すでに示したマニュアルを見てもらうとして、ここでは ZIP ファイルを作成するメソッドと解凍するメソッドを説明します。

名前空間

ライブラリの機能を使うには次の 2 つの名前空間が必要です。

using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Core;

ZIP ファイルを作成する

再利用性を考え、メソッドにしておきました。dirName で指定したディレクトリに含まれるファイルおよび下層のディレクトリも再帰的に検索し、ディレクトリ構造を維持したまま ZIP ファイルに格納します。ファイルを持たないディレクトリ(空のディレクトリ)があれば、ディレクトリ名だけを含みます。なお、dirName で指定したディレクトリ自体は含みません。

パスワードを指定すると、ZIP ファイルを解凍するときにパスワードを入力するダイアログボックスが表示されます。不要であれば、null にしてください。

圧縮時に発生するイベントを捕捉するように設定しておきました。完全なコードではありませんが参考にしてください。

// CSharpZip によるファイル/ディレクトリの圧縮
// dirName     : 圧縮対象のディレクトリ名
// zipFileName : ZIP ファイル名(フルパス可)
// password    : パスワード(不要のとき null)
private void CompressFilesByCSharpZip(string dirName, string zipFileName, string password)
{
  // サブディレクトリも再帰的に検索する
  bool recurse = true;

  // 圧縮時のイベントを設定する
  var events = new FastZipEvents();
  events.CompletedFile = new CompletedFileHandler(events_CompletedFile);
  events.DirectoryFailure = new DirectoryFailureHandler(events_DirectoryFailure);
  events.FileFailure = new FileFailureHandler(events_FileFailure);
  events.ProcessDirectory = new ProcessDirectoryHandler(events_ProcessDirectory);
  events.ProcessFile = new ProcessFileHandler(events_ProcessFile);
  events.Progress = new ProgressHandler(events_Progress);

  var fastZip = new FastZip(events);

  fastZip.CreateEmptyDirectories = true;

  // パスワードの設定
  if ((password != String.Empty) & (password != null))
    fastZip.Password = password;

  // 圧縮する
  fastZip.CreateZip(zipFileName, dirName, recurse, null, null);
}

// CompletedFile イベントのイベントハンドラ
private void events_CompletedFile(object sender, ScanEventArgs e)
{
  Debug.Print(String.Format("events_CompletedFile: {0}", e.Name));
}

  .... その他のイベントハンドラは省略する

メソッドを呼び出すコードは以下のとおりです。

    CompressFilesByCSharpZip(directoryName, zipFileName, null);

ZIP ファイルを解凍する

こちらもメソッドにしました。解凍先に同名ファイルがあるとき、デリゲートを使ってどのようにするかを判断できるようにしました。もちろん、常に上書きとか、常に上書きしないなどに設定することもできます。

ZIP ファイルに含まれるファイルの属性を無視する設定しました。元のファイルが ReadOnly 属性であったとしても解凍後のファイルは Archive 属性になります。また、ファイルの日時は元のままに維持する設定になっています。

// CSharpZip によるファイル/ディレクトリの解凍
// zipFileName : ZIP ファイル名(フルパス可)
// dirName     : 解凍先のディレクトリ名
private void DecompressFilesByCSharpZip(string zipFileName, string dirName)
{
  var fastZip = new FastZip();
  fastZip.CreateEmptyDirectories = true;
  fastZip.RestoreAttributesOnExtract = false;
  fastZip.RestoreDateTimeOnExtract = true;

  // 解凍する
  // このメソッドでは同名ファイルがあるとき、デリゲートで判断することにした
  fastZip.ExtractZip(zipFileName, dirName, FastZip.Overwrite.Prompt,
     new FastZip.ConfirmOverwriteDelegate(fastZip_ConfirmOverwrite), null, null, true);
}

// 解凍先に同名ファイルが存在するときの処理を実行するデリゲート
// 上書きするとき true、しないとき false を返す
private bool fastZip_ConfirmOverwrite(string fileName)
{
  Debug.Print(String.Format("fastZip_ConfirmOverwrite: {0}", fileName));

  return true;
}

メソッドを呼び出すコードは以下のとおりです。

    DecompressFilesByCSharpZip(zipFileName, dirName);

−以上−