DotNetZip(Ionic Zip Library)を使ってZIP書庫を作成する

今回から、フリー(Microsoft Public License (Ms-PL))のライブラリであるDotNetZipを使ってZIP書庫の作成、展開、書庫内のファイルリストの表示などを行う方法を紹介します。今回は、ZIP書庫を作成する方法です。

DotNetZipは、.NET Framework 2.0以上で使用できます。

この記事では、バージョン1.8のDotNetZipを使用しています。

DotNetZipは、CodePlexのDotNetZipのサイトからダウンロードできます。ここでは、"Ionic.Zip.dll"がVisual Studioの参照設定に追加されているものとして話を進めます。DotNetZipのアーカイバには"Ionic.Zip.Reduced.dll"というDLLも入っていますが、これは"Ionic.Zip.dll"から自己展開書庫を作成する機能などを削除してサイズを小さくしたものです。

ZIP書庫を作成する基本的な方法

ZIP書庫を作成してファイルやフォルダを圧縮する手順を簡単に説明すると、次のようになります。

  1. ZipFileオブジェクトを作成する。
  2. AddFileメソッドを使って、圧縮するファイルを追加する。AddDirectoryメソッドを使えば、フォルダ内のすべてのファイルを追加することもできる。
  3. Saveメソッドを使って、ZIP書庫を作成する。

以下のコードでは、1つのファイルと1つのフォルダを圧縮してZIP書庫を作成しています。この例ではパスワードやコメントを設定したり、それ以外の様々なオプションも使っているためコードが長くなっていますが、本当に必要なコードはほんの少しです。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
'作成するZIP書庫のパス 
Dim zipPath As String = "C:\test.zip"
'圧縮するファイルのパス 
Dim filePath As String = "C:\readme.txt"
'圧縮するフォルダのパス 
Dim folderPath As String = "C:\doc"
 
'ZipFileを作成する 
Using zip As New Ionic.Zip.ZipFile()
    'IBM437でエンコードできないファイル名やコメントをShift JISでエンコード 
    zip.ProvisionalAlternateEncoding = _
        System.Text.Encoding.GetEncoding("shift_jis")
    'IBM437でエンコードできないファイル名やコメントをUTF-8でエンコード 
    'zip.UseUnicodeAsNecessary = True
    '圧縮レベルを変更 
    zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression
    '圧縮せずに格納する 
    'zip.ForceNoCompression = True
    '必要な時はZIP64で圧縮する。デフォルトはNever。 
    zip.UseZip64WhenSaving = Ionic.Zip.Zip64Option.AsNecessary
    'エラーが出てもスキップする。デフォルトはThrow。 
    zip.ZipErrorAction = Ionic.Zip.ZipErrorAction.Skip
    'ZIP書庫にコメントを付ける 
    zip.Comment = "こんにちは。"
 
    'パスワードを付ける 
    zip.Password = "password"
    'AES 256ビット暗号化 
    zip.Encryption = Ionic.Zip.EncryptionAlgorithm.WinZipAes256
 
    'ファイルを追加する 
    zip.AddFile(filePath)
    '書庫内に"doc"というディレクトリを作って 
    ' そこにfilePathを格納するには次のようにする 
    'zip.AddFile(filePath, "doc")
 
    'フォルダを追加する 
    zip.AddDirectory(folderPath)
    '書庫内に"doc"というディレクトリを作って 
    ' そこにfolderPathを格納するには次のようにする 
    'zip.AddDirectory(folderPath, "doc")
 
    'ZIP書庫を作成する 
    zip.Save(zipPath)
End Using
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
//作成するZIP書庫のパス
string zipPath = @"C:\test.zip";
//圧縮するファイルのパス
string filePath = @"C:\readme.txt";
//圧縮するフォルダのパス
string folderPath = @"C:\doc";
 
//ZipFileを作成する
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
    //IBM437でエンコードできないファイル名やコメントをShift JISでエンコード
    zip.ProvisionalAlternateEncoding =
        System.Text.Encoding.GetEncoding("shift_jis");
    //IBM437でエンコードできないファイル名やコメントをUTF-8でエンコード
    //zip.UseUnicodeAsNecessary = true;
    //圧縮レベルを変更
    zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
    //圧縮せずに格納する
    //zip.ForceNoCompression = true;
    //必要な時はZIP64で圧縮する。デフォルトはNever。
    zip.UseZip64WhenSaving = Ionic.Zip.Zip64Option.AsNecessary;
    //エラーが出てもスキップする。デフォルトはThrow。
    zip.ZipErrorAction = Ionic.Zip.ZipErrorAction.Skip;
    //ZIP書庫にコメントを付ける
    zip.Comment = "こんにちは。";
 
    //パスワードを付ける
    zip.Password = "password";
    //AES 256ビット暗号化
    zip.Encryption = Ionic.Zip.EncryptionAlgorithm.WinZipAes256;
 
    //ファイルを追加する
    zip.AddFile(filePath);
    //書庫内に"doc"というディレクトリを作って
    // そこにfilePathを格納するには次のようにする
    //zip.AddFile(filePath, "doc");
 
    //フォルダを追加する
    zip.AddDirectory(folderPath);
    //書庫内に"doc"というディレクトリを作って
    // そこにfolderPathを格納するには次のようにする
    //zip.AddDirectory(folderPath, "doc");
 
    //ZIP書庫を作成する
    zip.Save(zipPath);
}

この例では、ProvisionalAlternateEncodingプロパティを使って文字コードをShift JISとしていますが、このようにするか、もしくはUseUnicodeAsNecessaryプロパティをtrueにしてUTF-8を使うようにしないと、日本語のファイル名やコメントが文字化けします。ZipFileのコンストラクタのパラメータとしてEncodingを渡すことによっても、ProvisionalAlternateEncodingプロパティを指定することができます(下の例ではそのようにしています)。

追加するファイルごとに設定を変更する

Password、Encryption、ProvisionalAlternateEncoding、ZipErrorAction、ForceNoCompressionなどのプロパティは、値を設定した後で追加されたファイルにだけその設定が適用されます。つまり、例えば、追加するファイルごとにパスワードを変えたいのであれば、下のコードのように、Passwordプロパティを設定してからAddFileメソッドを呼び出すことを繰り返せばよいことになります。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
'ZipFileを作成する 
Using zip As New Ionic.Zip.ZipFile(System.Text.Encoding.GetEncoding("shift_jis"))
    'パスワードを設定してファイルを追加 
    zip.Password = "11111111"
    zip.AddFile("C:\1.txt")
 
    'パスワードを変更してファイルを追加 
    zip.Password = "22222222"
    zip.AddFile("C:\2.txt")
 
    'ZIP書庫を作成する 
    zip.Save("C:\test.zip")
End Using
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
//ZipFileを作成する
using (Ionic.Zip.ZipFile zip =
    new Ionic.Zip.ZipFile(System.Text.Encoding.GetEncoding("shift_jis")))
{
    //パスワードを設定してファイルを追加
    zip.Password = "11111111";
    zip.AddFile(@"C:\1.txt");
 
    //パスワードを変更してファイルを追加
    zip.Password = "22222222";
    zip.AddFile(@"C:\2.txt");
 
    //ZIP書庫を作成する
    zip.Save(@"C:\test.zip");
}

追加するファイルごとに設定を変更する別の方法としては、AddFileメソッドで返されるZipEntryオブジェクトのプロパティを変更する方法もあります。以下にその方法を示します。ここではパスワードの他、更新日時やコメントも変更しています。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
'ZipFileを作成する 
Using zip As New Ionic.Zip.ZipFile(System.Text.Encoding.GetEncoding("shift_jis"))
    'パスワードや更新日時を設定してファイルを追加 
    Dim entry1 As Ionic.Zip.ZipEntry = zip.AddFile("C:\1.txt")
    entry1.Password = "11111111"
    entry1.LastModified = DateTime.Now
 
    'パスワードやコメントを変更してファイルを追加 
    Dim entry2 As Ionic.Zip.ZipEntry = zip.AddFile("C:\2.txt")
    entry2.Password = "22222222"
    entry2.Comment = "コメントです"
 
    'ZIP書庫を作成する 
    zip.Save("C:\test.zip")
End Using
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
//ZipFileを作成する
using (Ionic.Zip.ZipFile zip =
    new Ionic.Zip.ZipFile(System.Text.Encoding.GetEncoding("shift_jis")))
{
    //パスワードや更新日時を設定してファイルを追加
    Ionic.Zip.ZipEntry entry1 = zip.AddFile(@"C:\1.txt");
    entry1.Password = "11111111";
    entry1.LastModified = DateTime.Now;
 
    //パスワードやコメントを変更してファイルを追加
    Ionic.Zip.ZipEntry entry2 = zip.AddFile(@"C:\2.txt");
    entry2.Password = "22222222";
    entry2.Comment = "コメントです";
 
    //ZIP書庫を作成する
    zip.Save(@"C:\test.zip");
}

特定のファイルのみを圧縮する

例えば、拡張子が".txt"のファイルだけを圧縮するなどのように、ある名前のファイルだけを圧縮したいという場合は、AddSelectedFilesメソッドを使うと便利です。

下の例では、フォルダ"C:\doc"以下にあるファイルの内、拡張子が".txt"のファイルのみを圧縮しています。このように、ワイルドカード(* や ?)を使ってファイルを指定できます。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
'作成するZIP書庫のパス 
Dim zipPath As String = "C:\test.zip"
 
'圧縮するファイルの定義 
Dim selectionCriteria As String = "*.txt"
'圧縮するファイルのあるフォルダのパス 
Dim directoryOnDisk As String = "C:\doc"
'圧縮したファイルを格納する書庫内のディレクトリのパス 
Dim directoryPathInArchive As String = ""
'サブフォルダも対象とするか 
Dim recurseDirectories As Boolean = True
 
'ZipFileを作成する 
Using zip As New Ionic.Zip.ZipFile()
    zip.ProvisionalAlternateEncoding = _
        System.Text.Encoding.GetEncoding("shift_jis")
 
    '指定されたファイルを追加する 
    zip.AddSelectedFiles(selectionCriteria, directoryOnDisk, _
                         directoryPathInArchive, recurseDirectories)
 
    'ZIP書庫を作成する 
    zip.Save(zipPath)
End Using
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
//作成するZIP書庫のパス
string zipPath = @"C:\test.zip";
 
//圧縮するファイルの定義
string selectionCriteria = "*.txt";
//圧縮するファイルのあるフォルダのパス
string directoryOnDisk = @"C:\doc";
//圧縮したファイルを格納する書庫内のディレクトリのパス
string directoryPathInArchive = "";
//サブフォルダも対象とするか
bool recurseDirectories = true;
 
//ZipFileを作成する
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
    zip.ProvisionalAlternateEncoding =
        System.Text.Encoding.GetEncoding("shift_jis");
 
    //指定されたファイルを追加する
    zip.AddSelectedFiles(selectionCriteria, directoryOnDisk,
        directoryPathInArchive, recurseDirectories);
 
    //ZIP書庫を作成する
    zip.Save(zipPath);
}

AddSelectedFilesメソッドの3番目のパラメータdirectoryPathInArchiveについて補足しておきます。上記の例ではdirectoryPathInArchiveを空の文字列にしていますが、このようにするとファイルは書庫のルートに追加されます。しかしdirectoryPathInArchiveをnull(VB.NETでは、Nothing)にすると、追加するファイルの絶対パスがそのまま書庫でも使用されます。例えば上の例でdirectoryPathInArchiveをnullにして"C:\a\b\c\readme.txt"というファイルを圧縮すると、"a/b/c/readme.txt"として書庫に格納されます。

selectionCriteriaの書式

実はAddSelectedFilesメソッドはもっと多機能で、ファイルの日時(作成日時、更新日時、アクセス日時)、サイズ、属性によってファイルを選択することもできます。これらの条件は、AddSelectedFilesメソッドの1番目のパラメータであるselectionCriteriaに特別な書式の文字列を渡すことで指定できます。

例えば、ファイルのサイズが100バイト未満のファイルを対象とするならば、selectionCriteriaを"size < 100"とします。この時「<」 の部分には、 =、!=、>、>=、<、<= を使うことができます。また数字の部分は、キロバイトを表す k(または kb)や、メガバイトを表す m(または mb)、ギガバイトを表す g(または gb)を末尾に付けることができます。例えば2MB以下のファイルであれば、"size <= 2g"とできます。

更新日時が「2009年1月1日12時0分0秒以降」のファイルを対象とするならば、selectionCriteriaを"mtime >= 2009-01-01-12:00:00"とします。"mtime"は更新日時を表しますが、作成日時の場合は"ctime"、アクセス日時の場合は"atime"とします。日時の指定は、「YYYY-MM-DD-HH:mm:ss」の形式で記述します。「HH:mm:ss」を省略して「YYYY-MM-DD」とすることもできますが、この時日時には「00:00:00」が指定されたとみなされます。

ファイルの属性が隠しファイルでないファイルを対象とするならば、selectionCriteriaを"attributes != H"とします。「H」は隠しファイルを表しますが、読み取り専用は「R」、システムは「S」、アーカイブは「A」となります。

先のコードでは拡張子が".txt"のファイルを対象とするためにselectionCriteriaを"*.txt"としていましたが、正式には"name = *.txt"と書きます。ただし「name =」は省略できるため、"*.txt"と書くことができます。拡張子が".txt"以外のファイルを対象とするならば、"name != *.txt"とします。ファイル名を指定する部分には、「*」や「?」のワイルドカードを使うことができます。*1

さらに複数の条件を「AND」や「OR」でつないだり、括弧で優先順位を指定することができます。例えば、ファイルの作成日時が「2009年1月1日」のファイルか、アーカイブ属性のファイルを対象とするならば、selectionCriteriaを"(ctime >= 2009-01-01 AND ctime < 2009-01-02) OR attributes = A"とします。

自己展開書庫(SFX)を作成する

DotNetZipの大きな特徴は、自己展開書庫(SFX)を作成できることです。DotNetZipで作成される自己展開書庫は、.NET Framework 2.0以降がインストールされた環境で展開できます。

自己展開書庫を作成するには、今までSaveメソッドを使っていたところをSaveSelfExtractorメソッドに替えるだけです。以下にその例を示します。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
'圧縮するファイルのあるフォルダのパス 
Dim folderPath As String = "C:\doc"
 
'作成する自己展開書庫のパス 
Dim exeToGenerate As String = "C:\test.exe"
'Windowsアプリケーションとするか、コンソールアプリケーションとするか 
Dim flavor As Ionic.Zip.SelfExtractorFlavor = _
    Ionic.Zip.SelfExtractorFlavor.WinFormsApplication
'デフォルトの展開先のフォルダパス 
Dim defaultExtractDirectory As String = "C:\test"
'展開後実行するコマンド 
Dim postExtractCommandToExecute As String = "readme.txt"
'作成するEXEファイルのアイコンにするアイコンファイルのパス 
Dim iconFile As String = Nothing
 
'ZipFileを作成する 
Using zip As New Ionic.Zip.ZipFile()
    'IBM437でエンコードできないファイル名やコメントをUTF-8でエンコード 
    zip.UseUnicodeAsNecessary = True
 
    'フォルダを追加する 
    zip.AddDirectory(folderPath)
 
    '自己展開書庫を作成する 
    zip.SaveSelfExtractor(exeToGenerate, flavor, _
        defaultExtractDirectory, postExtractCommandToExecute, iconFile)
End Using
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
//圧縮するファイルのあるフォルダのパス
string folderPath = @"C:\doc";
 
//作成する自己展開書庫のパス
string exeToGenerate = @"C:\test.exe";
//Windowsアプリケーションとするか、コンソールアプリケーションとするか
Ionic.Zip.SelfExtractorFlavor flavor =
    Ionic.Zip.SelfExtractorFlavor.WinFormsApplication;
//デフォルトの展開先のフォルダパス
string defaultExtractDirectory = @"C:\test";
//展開後実行するコマンド
string postExtractCommandToExecute = "readme.txt";
//作成するEXEファイルのアイコンにするアイコンファイルのパス
string iconFile = null;
 
//ZipFileを作成する
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
    //IBM437でエンコードできないファイル名やコメントをUTF-8でエンコード
    zip.UseUnicodeAsNecessary = true;
 
    //フォルダを追加する
    zip.AddDirectory(folderPath);
 
    //自己展開書庫を作成する
    zip.SaveSelfExtractor(exeToGenerate, flavor,
        defaultExtractDirectory, postExtractCommandToExecute, iconFile);
}

SaveSelfExtractorメソッドのオーバーロードには幾つかありますが、ここではパラメータ数が一番多いものを使用しました。パラメータ数が最小のオーバーロードは、exeToGenerateとflavorの2つのパラメータしか持ちません。

私が試した限りでは、ProvisionalAlternateEncodingプロパティにShift JISを指定してもファイル名が日本語のファイルは文字化けしました。UseUnicodeAsNecessaryプロパティをtrueにすれば文字化けしなくなりました。

上記のコードで作成されたEXEファイルを実行すると、下の図のようなウィンドウが表示されます。もしpostExtractCommandToExecuteパラメータを指定しなければ、「Execute after unpack:」は表示されません。

dotnetzip1.png

flavorパラメータをConsoleApplicationにすると、コンソールアプリケーションになります。この時作成されるEXEファイルには、幾つかのコマンドラインを使用できます。コマンドラインに"-?"を指定したときに表示される説明は、以下のようなものでした。

C:\Documents and Settings\user>C:\test.exe -?
DotNetZip Command-Line Self Extractor, see http://DotNetZip.codeplex.com/
usage:
  test.exe [-o|-n] [-v] [-p password] [<directory>]
    Extracts entries from the archive. If any files to be extracted already
    exist, the program will stop.
  Options:
    -o   - overwrite any existing files upon extraction.
    -n   - do not overwrite any existing files upon extraction.
    -v   - verbose.

  default extract dir: C:\test

  test.exe -l
    Lists entries in the archive.

次回予告

次回はDotNetZipを使ってZIP書庫を展開する方法を紹介する予定です。

コメント

  • 大変参考にさせていただいております。 ver1.9系では、エンコードの指定の仕方が替わっているようですが、このページに記載のあるver1.8系という前提ですが Using zip As New Ionic.Zip.ZipFile(System.Text.Encoding.GetEncoding("shift_jis")) で ZipFileクラスインスタンスを作成し、AddSelectedFiles() を使って圧縮するファイルを追加する際に、追加するファイル名でASCIIとShift_jis混在で且つ"abcd(基本).xml"のような場合([注]:括弧が半角の場合)に AddSelectedFiles() メソッドで、"System.ArgumentException"が発生します。 "abcd(基本).xml"のような場合([注]:括弧が全角の場合)には例外は発生しません。 ZipFileクラスインスタンスを作成時にエンコードを指定せず、且つ zip.UseUnicodeAsNecessary = True を指定した場合も結果は同じでした。 これはやはり、ファイル名などの文字列を解析する際のエンコードの問題なのでしょうか? -- 山田 2012-01-18 (水) 15:31:41


ページ情報
  • カテゴリ : .NET
  • 作成日 : 2009-11-30 (月) 02:23:11
  • 作成者 : DOBON!
  • 最終編集日 : 2009-12-15 (火) 01:12:59
  • 最終編集者 : DOBON!

*1 ここで指定するファイル名にはディレクトリ名は含みません。
[ トップ ]   [ 編集 | 凍結 | 差分 | バックアップ | 添付 | 複製 | 名前変更 | リロード ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]