Dynamic Language SDK を使った ZIPアーカイブの使い方

C#などの言語でZIPアーカイブを取り扱うには、幾つかの方法があります。全てではないにしても、その代表的なものを以下に記載します。

  • J#のZipライブラリを使用する。
  • Windows Shell APIを使用する(COMを使うのが簡単)。
  • フリーのライブラリを使用する(たとえば、ここなど)。
  • 統合アーカイバ プロジェクトのライブラリを使用する。
  • 市販のコンポーネントを使用する。

これ以外にも、独自に作成したりと幾つかの方法を考えることができるでしょう。ここでは、Silverlight Dynamic Language SDKで提供されるChiron.exeユーティリティを利用してみたいと考えています。Chiron.exeは、IronPython、IronRuby、Managed JScriptを使ってSilverlightアプリを開発する時に使用するユーティリティです。このユーティリティで「Chiron /z:app.xap /d:App」を実行することで、XAPファイルを作成することができます。XAPファイルは、ZIPアーカイブの拡張子をXAPにしただけのファイル・フォーマットです。つまり、Chiron.exeユーティリティの中にZIPアーカイブを扱うライブラリがあるわけです。このChiron.exeのソースコードもDynamic Language SDKで提供されています。これ以外にも、IronPython 2.0やIronRubyプロジェクトのソースコードにもChiron.exeのソースコードが含まれています。これらのプロジェクトで配布されているソースコードはライセンスがMS-PLですから、MS-PLを守ればソースコードを流用することも可能になっています。今回、利用するソースコードは、以下の2つです。

  1. Chiron\Zip.cs (ZIPアーカイバのメインソース)
  2. Chiron\Crc32.cs (CRC計算用のヘルパー)

Zip.csには3つのクラスが定義されており、その中のZipArchiveクラスとZipArchiveFileクラスを利用します。ZipArchiveクラスが、Zipアーカイバそのものを扱うクラスであり、Zipアーカイバに含まれるエントリ(ファイル)がZipArchiveFileクラスのコレクションで扱います。つまり、ZipArchiveFileクラスがZipアーカイブに含まれる1エントリを扱うためのクラスになるのです。
 ZipArchiveクラスを利用する上で、必ず守らなければならない手順があります。それは以下のようなものです。

  1. ZipArchiveのインスタンス作成
  2. 各種操作(アーカイバの作成や展開など)
  3. ZipArchive.Closeメソッドの呼び出し

 次に良く使用するだろうと考えられるメンバーを以下にまとめます。

メンバー名 説   明
ZipArchive(string archivePath) コンストラクタで、読み取り専用のZIPアーカイブを開きます。archivePath:ZIPアーカイブのファイル名
ZipArchive(string archivePath, FileAccess access) コンストラクタで、読み書き用(FileAccess.ReadWrite)にZIPアーカイブを開きます。archivePath:ZIPアーカイブのファイル名access:ファイルのオープンモード(FileAccess.ReadWriteを指定します)
Countプロパティ ZIPアーカイブに含まれている要素数を戻します。
Filesプロパティ ZIPアーカイブに含まれているZipArchiveFileのコレクションを戻します。このコレクションを使うことで、ZIPアーカイブに含まれる様々な情報や個別の展開などを行うことができます。
CopyFromDirectory(string sourceDirectory, string targetDirectory) 指定したフォルダからZIPアーカイブへ追加します。sourceDirectory:ZIPアーカイブへ追加するフォルダtagetDirectory:ZIPアーカイブ上のルートフォルダを指定します。空文字は、ルート直下となります。
CopyToDirtectory(string sourceArchiveDirectory, string targetDirectory) ZIPアーカイブを指定したフォルダへ展開します。sourceArchiveDirectory:ZIPアーカイブ上の展開したいフォルダ名を指定します。空文字は、ルートとなり全てのエントリが展開されます。targetDirectory:展開先のフォルダを指定します。
CopyFromFile(string sourceFilePath, string targetArchivePath) ZIPアーカイブへ指定したファイルを追加します。sourceFilePath:ZIPアーカイブへ追加するファイルを指定します。targetArchivePath:ZIPアーカイブ内のフォルダを指定します。空文字は、ルートとなります。
CopyToFile(string sourceArchivePath, string targetFilePath) 指定したZIPアーカイブのエントリを指定したファイルへ展開します。sourceArchivePath:ZIPアーカイブのエントリの名前のインデクサ(ZipArchiveFile.Name)です。targetFilePath:展開先のファイル名をフルパスで指定します。
Close() ZipArchiveクラスのインスタンスで使用したリソースを解放します。

  これ以外にもメンバーはありますが、この程度が頻繁に使うものだと考えられます。ZipArchiveクラスのエントリになるZipArchiveFileクラスから、様々な情報を取得することができます。その代表的なメンバーを以下に示します。

メンバー名 説    明
Nameプロパティ ファイル名で、フルパス(ZIPアーカイブをルートとしています)で表現されます。ファイル名だけを取得するには、パス区切りで分割などして取り出します。
Lengthプロパティ ファイルサイズです。
LastWriteTimeプロパティ ファイルの最終更新日です。
ReadAllText()メソッド テキストファイルの場合に、その内容を文字列で取得します。

  後は圧縮されたサイズが参照したくなるかも知れませんが、ZipArchiveFileクラスで圧縮サイズを返すメンバーが用意されていません。このため自分で取得するメンバーを実装する必要があります(プライベート変数にcompressedDataが用意されているので、この変数のLengthなどを返すようにすれば取得することができます。もっともCopyFromFileメソッドを実行した直後は、compressedDataがnullになっていることに注意が必要です。

 ここまでで必要になるクラスやメンバーの説明が完了しました。以下に新しいZIPアーカイブを作成するサンプルコードを提示します。

 // 新規のアーカイブ作成
ZipArchive zipArchive = new ZipArchive(
                        "アーカイブ名", FileAccess.ReadWrite);
// アーカイブへ指定フォルダを追加
zipArchive.CopyFromDirectory(
                        "追加するフォルダ", "アーカイブ上のフォルダ名");
// アーカイブをクローズ
zipArchive.Close()
// アーカイブを開く
zipArchive = new ZipArchive("アーカイブ名");
// エントリを取得
foreach (ZipArchiveFile item in zipArchive.Files)
{
    // エントリの一覧などを処理する;
}
// アーカイブをクローズ
zipArchive.Close()

後は、説明したメンバーなどを活用すればZIPアーカイブに対する操作は一通りできるようになると思います。ここで使用したZipArchiveクラスでは、残念ながらパスワード付きZIPには対応していませんので、パスワード付きZIPを作成したい場合は、別の方法を使って下さい。

最後に、Windows エクスプローラで作成したZIPアーカイブをZipArchiveクラスで扱う場合の注意点を以下に記します。

  • ZipArchiveFile.Lengthプロパティがゼロのメンバーが存在します。
  • ZipArcihveクラスは、ZipArchiveFile.Lengethプロパティのゼロを想定していませんので、エラーになります。

この問題を回避する場合は、必要なメソッドに対処コードを追加する必要があります。