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書庫を作成してファイルやフォルダを圧縮する手順を簡単に説明すると、次のようになります。
- ZipFileオブジェクトを作成する。
- AddFileメソッドを使って、圧縮するファイルを追加する。AddDirectoryメソッドを使えば、フォルダ内のすべてのファイルを追加することもできる。
- 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
| | Dim zipPath As String = "C:\test.zip"
Dim filePath As String = "C:\readme.txt"
Dim folderPath As String = "C:\doc"
Using zip As New Ionic.Zip.ZipFile()
zip.ProvisionalAlternateEncoding = _
System.Text.Encoding.GetEncoding("shift_jis")
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression
zip.UseZip64WhenSaving = Ionic.Zip.Zip64Option.AsNecessary
zip.ZipErrorAction = Ionic.Zip.ZipErrorAction.Skip
zip.Comment = "こんにちは。"
zip.Password = "password"
zip.Encryption = Ionic.Zip.EncryptionAlgorithm.WinZipAes256
zip.AddFile(filePath)
zip.AddDirectory(folderPath)
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
| | string zipPath = @"C:\test.zip";
string filePath = @"C:\readme.txt";
string folderPath = @"C:\doc";
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
zip.ProvisionalAlternateEncoding =
System.Text.Encoding.GetEncoding("shift_jis");
zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
zip.UseZip64WhenSaving = Ionic.Zip.Zip64Option.AsNecessary;
zip.ZipErrorAction = Ionic.Zip.ZipErrorAction.Skip;
zip.Comment = "こんにちは。";
zip.Password = "password";
zip.Encryption = Ionic.Zip.EncryptionAlgorithm.WinZipAes256;
zip.AddFile(filePath);
zip.AddDirectory(folderPath);
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
| | 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.Save("C:\test.zip")
End Using
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| | 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.Save(@"C:\test.zip");
}
|
追加するファイルごとに設定を変更する別の方法としては、AddFileメソッドで返されるZipEntryオブジェクトのプロパティを変更する方法もあります。以下にその方法を示します。ここではパスワードの他、更新日時やコメントも変更しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| | 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.Save("C:\test.zip")
End Using
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| | 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.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
| | 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
Using zip As New Ionic.Zip.ZipFile()
zip.ProvisionalAlternateEncoding = _
System.Text.Encoding.GetEncoding("shift_jis")
zip.AddSelectedFiles(selectionCriteria, directoryOnDisk, _
directoryPathInArchive, recurseDirectories)
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
| | string zipPath = @"C:\test.zip";
string selectionCriteria = "*.txt";
string directoryOnDisk = @"C:\doc";
string directoryPathInArchive = "";
bool recurseDirectories = true;
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
zip.ProvisionalAlternateEncoding =
System.Text.Encoding.GetEncoding("shift_jis");
zip.AddSelectedFiles(selectionCriteria, directoryOnDisk,
directoryPathInArchive, recurseDirectories);
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"
Dim flavor As Ionic.Zip.SelfExtractorFlavor = _
Ionic.Zip.SelfExtractorFlavor.WinFormsApplication
Dim defaultExtractDirectory As String = "C:\test"
Dim postExtractCommandToExecute As String = "readme.txt"
Dim iconFile As String = Nothing
Using zip As New Ionic.Zip.ZipFile()
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";
Ionic.Zip.SelfExtractorFlavor flavor =
Ionic.Zip.SelfExtractorFlavor.WinFormsApplication;
string defaultExtractDirectory = @"C:\test";
string postExtractCommandToExecute = "readme.txt";
string iconFile = null;
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
{
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:」は表示されません。
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 を指定した場合も結果は同じでした。 これはやはり、ファイル名などの文字列を解析する際のエンコードの問題なのでしょうか? -- 山田