DotNetZip(Ionic Zip Library)を使ってZIP書庫を展開する †
前回はDotNetZipを使ってZIP書庫を作成する方法を紹介しました。今回はDotNetZipを使ってZIP書庫を展開(解凍)する方法を中心に紹介します。
ZIP書庫を展開する基本的な方法 †
ZIP書庫を展開する基本的な手順は、次のようになります。
- ZipFile.Readメソッドを使ってZipFileオブジェクトを作成する。
- For Each(foreach)やインデクサを使って、展開したいファイルを表すZipEntryをZipFileオブジェクトから探す。
- ZipEntry.Extractメソッドでファイルを展開する。なお、展開先フォルダは自動的に作成される。
このような方法で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
| | Dim zipPath As String = "C:\test.zip"
Dim folderPath As String = "C:\temp"
Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
zipPath, System.Text.Encoding.GetEncoding("shift_jis"))
zip.ExtractExistingFile = _
Ionic.Zip.ExtractExistingFileAction.OverwriteSilently
For Each entry As Ionic.Zip.ZipEntry In zip
entry.Extract(folderPath)
Next
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
| | string zipPath = @"C:\test.zip";
string folderPath = @"C:\temp";
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(
zipPath, System.Text.Encoding.GetEncoding("shift_jis")))
{
zip.ExtractExistingFile =
Ionic.Zip.ExtractExistingFileAction.OverwriteSilently;
foreach (Ionic.Zip.ZipEntry entry in zip)
{
entry.Extract(folderPath);
}
}
|
補足:ZIP書庫内のすべてのファイルを展開するには、ZipFile.ExtractAllメソッドを使うこともできます。
ZipFile.Readメソッドでなく、ZipFileのコンストラクタでも、既存のZIP書庫を開いてZipFileオブジェクトを作成することができます。しかしReadメソッドで文字コードを指定しないと、Shift JISなどでエンコードしたファイル名は文字化けします。一般的なアーカイバが作成するZIP書庫は通常Shift JISでファイル名がエンコードされていますので、ZipFile.Readメソッドを使う必要があります。
ただし、UseUnicodeAsNecessaryをtrueにして作成した書庫のファイルは、文字コードやUseUnicodeAsNecessaryを設定しなくても文字化けせずに展開できました。よってこの場合は、ZipFile.Readメソッドを使わなくても大丈夫でした。
残念ながら、私の試した限りでは、Readメソッドで文字コードを設定しても、UseUnicodeAsNecessaryをtrueにしても、日本語のコメントは文字化けしました。
1つのファイルを展開する †
ZipFileのインデクサを使えば、エントリ名をキーにしてZipEntryを取得できます。以下にこの方法でファイル名が"readme.txt"のファイルを展開する例を示します。
1
2
3
4
5
6
7
8
| | Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis"))
Dim entry As Ionic.Zip.ZipEntry = zip("readme.txt")
entry.Extract("C:\temp")
End Using
|
1
2
3
4
5
6
7
8
9
10
| | using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(
@"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis")))
{
Ionic.Zip.ZipEntry entry = zip["readme.txt"];
entry.Extract(@"C:\temp");
}
|
特定のファイルのみを展開する †
前回の特定のファイルのみを圧縮する方法で紹介したAddSelectedFilesメソッドと同じように、ExtractSelectedEntriesメソッドにより、特定のファイルのみを展開することができます。
ExtractSelectedEntriesメソッドの1番目のパラメータであるselectionCriteriaの書式は、特定のファイルのみを圧縮する方法で説明したselectionCriteriaの書式と同じですので、詳しくはそちらをご覧ください。
以下に、拡張子が".txt"のファイルのみを展開する例を示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| | Dim zipPath As String = "C:\test.zip"
Dim selectionCriteria As String = "*.txt"
Dim directoryPathInArchive As String = Nothing
Dim extractDirectory As String = "C:\temp"
Dim extractExistingFile As Ionic.Zip.ExtractExistingFileAction = _
Ionic.Zip.ExtractExistingFileAction.DoNotOverwrite
Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
zipPath, System.Text.Encoding.GetEncoding("shift_jis"))
zip.ExtractSelectedEntries(selectionCriteria, directoryPathInArchive, _
extractDirectory, extractExistingFile)
End Using
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| | string zipPath = @"C:\test.zip";
string selectionCriteria = @"*.txt";
string directoryPathInArchive = null;
string extractDirectory = @"C:\temp";
Ionic.Zip.ExtractExistingFileAction extractExistingFile =
Ionic.Zip.ExtractExistingFileAction.DoNotOverwrite;
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(
zipPath, System.Text.Encoding.GetEncoding("shift_jis")))
{
zip.ExtractSelectedEntries(selectionCriteria, directoryPathInArchive,
extractDirectory, extractExistingFile);
}
|
圧縮、展開時に進行状況を表示する †
ZIP書庫を作成するときに進行状況を表示するには、SaveProgressイベントを使用します。SaveProgressイベントでは、どのファイルをどれだけ(何バイト)書き込んだかなどの情報を知ることができます。
ZIP書庫を展開するときは、ExtractProgressイベントで進行状況を知ることができます。ExtractProgressイベントでは、どのファイルを何バイト展開したかなどの情報を知ることができます。
ZipFileクラスにはこれらのイベント以外に、AddProgressとZipErrorという2つのイベントがあります。AddProgressイベントは、ZipFileのAddFileやAddDirectoryメソッドなどでファイルが追加されるときに発生します。AddDirectoryメソッドなどで大量のファイルを追加するときに、どのファイルが追加されたかを知るのに役に立ちます。ZipErrorイベントは、書庫を作成するとき、圧縮するファイルを開けないなどの理由でエラーが発生すると発生します。
補足:AddProgressイベントハンドラでAddProgressEventArgs.CancelをTrueにしても、ファイルの追加を中止できません。
SaveProgressとExtractProgressイベントを使って、圧縮、展開時に進行状況を表示する例を以下に示します。
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
| | Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles Button1.Click
Using zip As New Ionic.Zip.ZipFile( _
System.Text.Encoding.GetEncoding("shift_jis"))
AddHandler zip.SaveProgress, AddressOf Me.zip_SaveProgress
zip.AddDirectory("C:\doc")
zip.Save("C:\test.zip")
End Using
End Sub
Private Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles Button2.Click
Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis"))
AddHandler zip.ExtractProgress, AddressOf Me.zip_ExtractProgress
zip.ExtractAll("C:\temp", _
Ionic.Zip.ExtractExistingFileAction.OverwriteSilently)
End Using
End Sub
Private Sub zip_SaveProgress(ByVal sender As Object, _
ByVal e As Ionic.Zip.SaveProgressEventArgs)
If e.EventType = _
Ionic.Zip.ZipProgressEventType.Saving_Started Then
Console.WriteLine("{0} の作成開始", e.ArchiveName)
ElseIf e.EventType = _
Ionic.Zip.ZipProgressEventType.Saving_BeforeWriteEntry Then
Console.WriteLine("{0} の書き込み開始", e.CurrentEntry.FileName)
ElseIf e.EventType = _
Ionic.Zip.ZipProgressEventType.Saving_EntryBytesRead Then
Console.WriteLine("{0}/{1} バイト 書き込みました", _
e.BytesTransferred, e.TotalBytesToTransfer)
ElseIf e.EventType = _
Ionic.Zip.ZipProgressEventType.Saving_AfterWriteEntry Then
Console.WriteLine("{0} の書き込み終了", e.CurrentEntry.FileName)
Console.WriteLine("{0} 個中 {1} 個のエントリの書き込みが完了しました", _
e.EntriesTotal, e.EntriesSaved)
ElseIf e.EventType = _
Ionic.Zip.ZipProgressEventType.Saving_Completed Then
Console.WriteLine("{0} の作成終了", e.ArchiveName)
End If
End Sub
Private Sub zip_ExtractProgress(ByVal sender As Object, _
ByVal e As Ionic.Zip.ExtractProgressEventArgs)
If e.EventType = _
Ionic.Zip.ZipProgressEventType.Extracting_BeforeExtractEntry Then
Console.WriteLine("{0} の展開を開始", e.CurrentEntry.FileName)
Console.WriteLine("展開先:{0}", e.ExtractLocation)
ElseIf e.EventType = _
Ionic.Zip.ZipProgressEventType.Extracting_EntryBytesWritten Then
Console.WriteLine("{0}/{1} バイト展開しました", _
e.BytesTransferred, e.TotalBytesToTransfer)
ElseIf e.EventType = _
Ionic.Zip.ZipProgressEventType.Extracting_AfterExtractEntry Then
Console.WriteLine("{0} の展開が終了", e.CurrentEntry.FileName)
End If
End Sub
|
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
| | private void Button1_Click(object sender, EventArgs e)
{
using (Ionic.Zip.ZipFile zip =
new Ionic.Zip.ZipFile(System.Text.Encoding.GetEncoding("shift_jis")))
{
zip.SaveProgress += this.zip_SaveProgress;
zip.AddDirectory(@"C:\doc");
zip.Save(@"C:\test.zip");
}
}
private void Button2_Click(object sender, EventArgs e)
{
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(
@"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis")))
{
zip.ExtractProgress += this.zip_ExtractProgress;
zip.ExtractAll(@"C:\temp",
Ionic.Zip.ExtractExistingFileAction.OverwriteSilently);
}
}
private void zip_SaveProgress(
object sender, Ionic.Zip.SaveProgressEventArgs e)
{
if (e.EventType ==
Ionic.Zip.ZipProgressEventType.Saving_Started)
{
Console.WriteLine("{0} の作成開始", e.ArchiveName);
}
else if (e.EventType ==
Ionic.Zip.ZipProgressEventType.Saving_BeforeWriteEntry)
{
Console.WriteLine("{0} の書き込み開始", e.CurrentEntry.FileName);
}
else if (e.EventType ==
Ionic.Zip.ZipProgressEventType.Saving_EntryBytesRead)
{
Console.WriteLine("{0}/{1} バイト 書き込みました",
e.BytesTransferred, e.TotalBytesToTransfer);
}
else if (e.EventType ==
Ionic.Zip.ZipProgressEventType.Saving_AfterWriteEntry)
{
Console.WriteLine("{0} の書き込み終了", e.CurrentEntry.FileName);
Console.WriteLine("{0} 個中 {1} 個のエントリの書き込みが完了しました",
e.EntriesTotal, e.EntriesSaved);
}
else if (e.EventType ==
Ionic.Zip.ZipProgressEventType.Saving_Completed)
{
Console.WriteLine("{0} の作成終了", e.ArchiveName);
}
}
private void zip_ExtractProgress(
object sender, Ionic.Zip.ExtractProgressEventArgs e)
{
if (e.EventType ==
Ionic.Zip.ZipProgressEventType.Extracting_BeforeExtractEntry)
{
Console.WriteLine("{0} の展開を開始", e.CurrentEntry.FileName);
Console.WriteLine("展開先:{0}", e.ExtractLocation);
}
else if (e.EventType ==
Ionic.Zip.ZipProgressEventType.Extracting_EntryBytesWritten)
{
Console.WriteLine("{0}/{1} バイト展開しました",
e.BytesTransferred, e.TotalBytesToTransfer);
}
else if (e.EventType ==
Ionic.Zip.ZipProgressEventType.Extracting_AfterExtractEntry)
{
Console.WriteLine("{0} の展開が終了", e.CurrentEntry.FileName);
}
}
|
展開したファイルを上書きするかユーザーに問い合わせる †
デフォルトでは、展開先に同名のファイルが存在すると例外が発生します。この動作を変更するには、ZipFile.ExtractExistingFileプロパティを変更します。ExtractExistingFileプロパティをOverwriteSilentlyにすると常に上書きし、DoNotOverwriteにすると常に上書きしません。
もしファイルを上書きするかユーザーに問い合わせるようにするならば、ExtractExistingFileプロパティをInvokeExtractProgressEventにします。このようにすると、展開しようとしているファイルと同名のファイルが既に存在しているとき、ExtractProgressイベントが発生し、ExtractProgressEventArgs.EventTypeがExtracting_ExtractEntryWouldOverwriteになります。この時、ExtractProgressEventArgs.CurrentEntryプロパティで得られるZipEntryオブジェクトのExtractExistingFileプロパティを変更することで、上書きするかしないかを指定できます。
さらに、ExtractProgressEventArgs.Cancelプロパティをtrueにして展開をキャンセルすることもできます。この時、これ以降のすべてのファイルの展開がキャンセルされます。
上書きするかをメッセージボックスでユーザーに問い合わせ、「はい」ボタンを押したときは上書きし、「いいえ」ボタンを押したときは上書きせず、「キャンセル」ボタンを押したときは以降の展開をキャンセルするようにした例を以下に示します。
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
47
| | Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) _
Handles Button1.Click
Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis"))
AddHandler zip.ExtractProgress, AddressOf Me.zip_ExtractProgress
zip.ExtractExistingFile = _
Ionic.Zip.ExtractExistingFileAction.InvokeExtractProgressEvent
zip.ExtractAll("C:\temp")
End Using
End Sub
Private Sub zip_ExtractProgress(ByVal sender As Object, _
ByVal e As Ionic.Zip.ExtractProgressEventArgs)
If e.EventType = _
Ionic.Zip.ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite Then
Dim filePath As String = System.IO.Path.Combine( _
e.ExtractLocation, e.CurrentEntry.FileName.Replace("/"c, "\"c))
Dim res As DialogResult = MessageBox.Show(Me, _
"'" & filePath & "'はすでに存在します。" & vbCrLf & _
"'はい'で上書き 'いいえ'で何もしない 'キャンセル'で中止", _
"上書きの確認", _
MessageBoxButtons.YesNoCancel, _
MessageBoxIcon.Question)
If res = DialogResult.Yes Then
e.CurrentEntry.ExtractExistingFile = _
Ionic.Zip.ExtractExistingFileAction.OverwriteSilently
ElseIf res = DialogResult.No Then
e.CurrentEntry.ExtractExistingFile = _
Ionic.Zip.ExtractExistingFileAction.DoNotOverwrite
ElseIf res = DialogResult.Cancel Then
e.Cancel = True
End If
End If
End Sub
|
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
47
48
49
50
51
52
53
54
55
| | private void Button1_Click(object sender, EventArgs e)
{
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(
@"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis")))
{
zip.ExtractProgress += zip_ExtractProgress;
zip.ExtractExistingFile =
Ionic.Zip.ExtractExistingFileAction.InvokeExtractProgressEvent;
zip.ExtractAll(@"C:\temp");
}
}
private void zip_ExtractProgress(
object sender, Ionic.Zip.ExtractProgressEventArgs e)
{
if (e.EventType ==
Ionic.Zip.ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite)
{
string filePath = System.IO.Path.Combine(
e.ExtractLocation, e.CurrentEntry.FileName.Replace('/', '\\'));
//ダイアログを表示する
DialogResult res = MessageBox.Show(this,
"'" + filePath + "'はすでに存在します。\n" +
"'はい'で上書き 'いいえ'で何もしない 'キャンセル'で中止",
"上書きの確認",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question);
if (res == DialogResult.Yes)
{
//上書きする
e.CurrentEntry.ExtractExistingFile =
Ionic.Zip.ExtractExistingFileAction.OverwriteSilently;
}
else if (res == DialogResult.No)
{
//上書きしない
e.CurrentEntry.ExtractExistingFile =
Ionic.Zip.ExtractExistingFileAction.DoNotOverwrite;
}
else if (res == DialogResult.Cancel)
{
//展開を中止する
e.Cancel = true;
}
}
}
|
コメント †
- 参考にさせていただきありがとうございます。 -- oo
- 質問があるのですが、プログレスバーで進捗状況を表示しながらZipファイルを作成したいのですが、サンプルコードを載せていただけたりできないでしょうか?お手数ではございますがよろしくお願いします。 -- oo
- パスワードのプロパティの設定順序気づかなかったので助かりました。 -- trsgr
- 読み取り専用ファイルの圧縮でエラーが出ます。対処方法を教えて下さい。 -- kanaisun
- バージョンの問題でしょうか? Ionic.Zip.ZipFile.Readの第二引数が違っております。 -- furu