2009/12/15
.NETプログラミング研究 第94号
┏第94号━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ .NETプログラミング研究 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
──<メニュー>───────────────────────
■.NET Tips
・DotNetZip(Ionic Zip Library)を使ってZIP書庫を展開する
・ZIP書庫を展開する基本的な方法
・1つのファイルを展開する
・特定のファイルのみを展開する
・圧縮、展開時に進行状況を表示する
・展開したファイルを上書きするかユーザーに問い合わせる
───────────────────────────────
───────────────────────────────
■Web版について
───────────────────────────────
メールでは表示できない画像や表などはWeb版に掲載しています。また、
記事があまりに長い場合は、メールでは300行を目安に短くなる場合が
あります。
[URL].NETプログラミング研究 Web版
http://wiki.dobon.net/index.php?.NET%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0%B8%A6%B5%E6%2F94
───────────────────────────────
■.NET Tips
───────────────────────────────
●DotNetZip(Ionic Zip Library)を使ってZIP書庫を展開する
前回はDotNetZipを使ってZIP書庫を作成する方法を紹介しました。今回
はDotNetZipを使ってZIP書庫を展開(解凍)する方法を中心に紹介しま
す。
★ZIP書庫を展開する基本的な方法
ZIP書庫を展開する基本的な手順は、次のようになります。
1.ZipFile.Readメソッドを使ってZipFileオブジェクトを作成する。
2.For Each(foreach)やインデクサを使って、展開したいファイルを表
すZipEntryをZipFileオブジェクトから探す。
3.ZipEntry.Extractメソッドでファイルを展開する。なお、展開先フォ
ルダは自動的に作成される。
このような方法でZIP書庫内のすべてのファイルを展開する例を以下に
示します。
‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
'展開するZIP書庫のパス
Dim zipPath As String = "C:\test.zip"
'展開先のフォルダのパス
Dim folderPath As String = "C:\temp"
'ZipFileを作成する
Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
zipPath, System.Text.Encoding.GetEncoding("shift_jis"))
'パスワードが設定されているときは、
'zip.Password = "password"
'または、ZipEntry.ExtractWithPasswordメソッドで展開する
'展開先に同名のファイルがあれば上書きする
zip.ExtractExistingFile = _
Ionic.Zip.ExtractExistingFileAction.OverwriteSilently
'DoNotOverwriteで上書きしない。Throwで例外をスロー。既定値はThrow。
'ZipEntry.Extractに指定して展開することもできる
'フォルダ構造を無視する
'zip.FlattenFoldersOnExtract = True
'ZIP書庫内のエントリを取得
For Each entry As Ionic.Zip.ZipEntry In zip
'エントリを展開する
entry.Extract(folderPath)
Next
End Using
‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
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.Password = "password";
//または、ZipEntry.ExtractWithPasswordメソッドで展開する
//展開先に同名のファイルがあれば上書きする
zip.ExtractExistingFile =
Ionic.Zip.ExtractExistingFileAction.OverwriteSilently;
//DoNotOverwriteで上書きしない。Throwで例外をスロー。既定値はThrow。
//ZipEntry.Extractに指定して展開することもできる
//フォルダ構造を無視する
//zip.FlattenFoldersOnExtract = true;
//ZIP書庫内のエントリを取得
foreach (Ionic.Zip.ZipEntry entry in zip)
{
//エントリを展開する
entry.Extract(folderPath);
}
}
‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
補足: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"のファイルを
展開する例を示します。
‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis"))
'"readme.txt"のZipEntryを取得する
'見つからなかったときはNothingを返す
Dim entry As Ionic.Zip.ZipEntry = zip("readme.txt")
'エントリを展開する
entry.Extract("C:\temp")
End Using
‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(
@"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis")))
{
//"readme.txt"のZipEntryを取得する
//見つからなかったときはnullを返す
Ionic.Zip.ZipEntry entry = zip["readme.txt"];
//エントリを展開する
entry.Extract(@"C:\temp");
}
‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
☆特定のファイルのみを展開する
前回の特定のファイルのみを圧縮する方法で紹介したAddSelectedFiles
メソッドと同じように、ExtractSelectedEntriesメソッドにより、特定
のファイルのみを展開することができます。
ExtractSelectedEntriesメソッドの1番目のパラメータである
selectionCriteriaの書式は、特定のファイルのみを圧縮する方法で説
明したselectionCriteriaの書式と同じですので、詳しくはそちらをご
覧ください。
以下に、拡張子が".txt"のファイルのみを展開する例を示します。
‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
'展開するZIP書庫のパス
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
'ZipFileを作成する
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
‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
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);
}
‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
★圧縮、展開時に進行状況を表示する
ZIP書庫を作成するときに進行状況を表示するには、SaveProgressイベ
ントを使用します。SaveProgressイベントでは、どのファイルをどれだ
け(何バイト)書き込んだかなどの情報を知ることができます。
ZIP書庫を展開するときは、ExtractProgressイベントで進行状況を知る
ことができます。ExtractProgressイベントでは、どのファイルを何バ
イト展開したかなどの情報を知ることができます。
ZipFileクラスにはこれらのイベント以外に、AddProgressとZipErrorと
いう2つのイベントがあります。AddProgressイベントは、ZipFileの
AddFileやAddDirectoryメソッドなどでファイルが追加されるときに発
生します。AddDirectoryメソッドなどで大量のファイルを追加するとき
に、どのファイルが追加されたかを知るのに役に立ちます。ZipErrorイ
ベントは、書庫を作成するとき、圧縮するファイルを開けないなどの理
由でエラーが発生すると発生します。
補足:AddProgressイベントハンドラでAddProgressEventArgs.Cancelを
Trueにしても、ファイルの追加を中止できません。
SaveProgressとExtractProgressイベントを使って、圧縮、展開時に進
行状況を表示する例を以下に示します。
‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
'書庫を作成する
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"))
'SaveProgressイベントハンドラを追加する
AddHandler zip.SaveProgress, AddressOf Me.zip_SaveProgress
'フォルダを追加する
zip.AddDirectory("C:\doc")
'ZIP書庫を作成する
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"))
'ExtractProgressイベントハンドラを追加する
AddHandler zip.ExtractProgress, AddressOf Me.zip_ExtractProgress
'すべてのファイルを展開する
zip.ExtractAll("C:\temp", _
Ionic.Zip.ExtractExistingFileAction.OverwriteSilently)
End Using
End Sub
'SaveProgressイベントハンドラ
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)
'e.Cancel = True
'とすると、書庫の作成が中止される
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
'ExtractProgressイベントハンドラ
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
‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
private void Button1_Click(object sender, EventArgs e)
{
using (Ionic.Zip.ZipFile zip =
new Ionic.Zip.ZipFile(System.Text.Encoding.GetEncoding("shift_jis")))
{
//SaveProgressイベントハンドラを追加する
zip.SaveProgress += this.zip_SaveProgress;
//フォルダを追加する
zip.AddDirectory(@"C:\doc");
//ZIP書庫を作成する
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")))
{
//ExtractProgressイベントハンドラを追加する
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);
//e.Cancel = true;
//とすると、書庫の作成が中止される
}
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);
}
}
‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
★展開したファイルを上書きするかユーザーに問い合わせる
デフォルトでは、展開先に同名のファイルが存在すると例外が発生しま
す。この動作を変更するには、ZipFile.ExtractExistingFileプロパテ
ィを変更します。ExtractExistingFileプロパティをOverwriteSilently
にすると常に上書きし、DoNotOverwriteにすると常に上書きしません。
もしファイルを上書きするかユーザーに問い合わせるようにするならば、
ExtractExistingFileプロパティをInvokeExtractProgressEventにしま
す。このようにすると、展開しようとしているファイルと同名のファイ
ルが既に存在しているとき、ExtractProgressイベントが発生し、
ExtractProgressEventArgs.EventTypeがExtracting_
ExtractEntryWouldOverwriteになります。この時、
ExtractProgressEventArgs.CurrentEntryプロパティで得られる
ZipEntryオブジェクトのExtractExistingFileプロパティを変更するこ
とで、上書きするかしないかを指定できます。
さらに、ExtractProgressEventArgs.Cancelプロパティをtrueにして展
開をキャンセルすることもできます。この時、これ以降のすべてのファ
イルの展開がキャンセルされます。
上書きするかをメッセージボックスでユーザーに問い合わせ、「はい」
ボタンを押したときは上書きし、「いいえ」ボタンを押したときは上書
きせず、「キャンセル」ボタンを押したときは以降の展開をキャンセル
するようにした例を以下に示します。
‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
'Button1のClickイベントハンドラ
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"))
'ExtractProgressイベントハンドラを追加する
AddHandler zip.ExtractProgress, AddressOf Me.zip_ExtractProgress
'ExtractProgressイベントで上書きするか指定できるようにする
zip.ExtractExistingFile = _
Ionic.Zip.ExtractExistingFileAction.InvokeExtractProgressEvent
'すべてのファイルを展開する
zip.ExtractAll("C:\temp")
End Using
End Sub
'ExtractProgressイベントハンドラ
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
‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
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")))
{
//ExtractProgressイベントハンドラを追加する
zip.ExtractProgress += zip_ExtractProgress;
//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;
}
}
}
‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥
===============================
■ここで示したコードの多くはまずC#で書き、それを「Convert C# to
VB.NET」でVB.NETのコードに変換し、修正を加えたものです。
[URL]Convert C# to VB.NET
http://www.developerfusion.com/tools/convert/csharp-to-vb/
■このマガジンの購読、購読中止、バックナンバー、説明に関しては
次のページをご覧ください。
http://www.mag2.com/m/0000104516.htm
■発行人・編集人:どぼん!
http://dobon.net
■ご質問等はメールではなく、掲示板へお願いいたします。
http://dobon.net/vb/bbs.html
■メールは下記URLのフォームメールから送信してください。
http://dobon.net/mail.html
Copyright (c) DOBON! All rights reserved.
===============================


