DotNetZip(Ionic Zip Library)を使ってZIP書庫のリスト表示などを行う †
書庫内のエントリのリストを表示する †
前回のZIP書庫を展開する方法で紹介したように、ZipFileはZipEntryのコレクションとしての機能がありますので、書庫内のエントリ情報をZipEntryオブジェクトで取得するのは簡単です。ZipEntryオブジェクトにより、エントリ名やタイムスタンプ、圧縮前と後のサイズ、圧縮率、圧縮方法、コメント、CRCなどの情報を取得できます。
ZipFileオブジェクトをFor Each(foreach)でまわしてZipEntryを取得することで、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
| | Dim zipPath As String = "C:\test.zip"
Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
zipPath, System.Text.Encoding.GetEncoding("shift_jis"))
If String.IsNullOrEmpty(zip.Comment) Then
Console.WriteLine("コメント:{0}", zip.Comment)
End If
For Each entry As Ionic.Zip.ZipEntry In zip
If entry.IsDirectory Then
Console.WriteLine("ディレクトリ名:{0}", entry.FileName)
Console.WriteLine()
Else
Console.WriteLine("ファイル名:{0}", entry.FileName)
Console.WriteLine("更新日時:{0}", entry.ModifiedTime)
Console.WriteLine("サイズ:{0}バイト", entry.UncompressedSize)
Console.WriteLine("格納サイズ:{0}バイト", entry.CompressedSize)
Console.WriteLine("圧縮率:{0}%", entry.CompressionRatio)
Console.WriteLine("CRC32:{0:X}", entry.Crc)
Console.WriteLine("パスワード:{0}", entry.UsesEncryption)
Console.WriteLine()
End If
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
30
31
32
33
34
35
36
37
38
| | string zipPath = @"C:\test.zip";
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(
zipPath, System.Text.Encoding.GetEncoding("shift_jis")))
{
if (string.IsNullOrEmpty(zip.Comment))
{
Console.WriteLine("コメント:{0}", zip.Comment);
}
foreach (Ionic.Zip.ZipEntry entry in zip)
{
if (entry.IsDirectory)
{
Console.WriteLine("ディレクトリ名:{0}", entry.FileName);
Console.WriteLine();
}
else
{
Console.WriteLine("ファイル名:{0}", entry.FileName);
Console.WriteLine("更新日時:{0}", entry.ModifiedTime);
Console.WriteLine("サイズ:{0}バイト", entry.UncompressedSize);
Console.WriteLine("格納サイズ:{0}バイト", entry.CompressedSize);
Console.WriteLine("圧縮率:{0}%", entry.CompressionRatio);
Console.WriteLine("CRC32:{0:X}", entry.Crc);
Console.WriteLine("パスワード:{0}", entry.UsesEncryption);
Console.WriteLine();
}
}
}
|
エントリの名前のリストだけであれば、ZipFile.EntryFileNamesプロパティでも取得できます。
1
2
3
4
5
6
7
8
9
10
11
| | Dim zipPath As String = "C:\test.zip"
Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
zipPath, System.Text.Encoding.GetEncoding("shift_jis"))
For Each entryName As String In zip.EntryFileNames
Console.WriteLine(entryName)
Next
End Using
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| | string zipPath = @"C:\test.zip";
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(
zipPath, System.Text.Encoding.GetEncoding("shift_jis")))
{
foreach (string entryName in zip.EntryFileNames)
{
Console.WriteLine(entryName);
}
}
|
ある条件のエントリをリスト表示する †
ZipFile.SelectEntriesメソッドを使用すると、エントリの名前、タイムスタンプ、サイズ、属性を条件として、条件に合ったエントリをZipEntryのコレクションとして取得できあます。
エントリを選別する条件としてSelectEntriesメソッドに渡すselectionCriteriaパラメータは、前々回紹介したAddSelectedFilesメソッドのselectionCriteriaパラメータの書式と同じですので、詳しくはそちらをご覧ください。
下の例ではSelectEntriesメソッドを使って.txt拡張子のエントリを取得して、その名前を列挙しています。
1
2
3
4
5
6
7
8
9
10
11
| | Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read( _
"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis"))
Dim entries As ICollection(Of Ionic.Zip.ZipEntry) = zip.SelectEntries("*.txt")
For Each entry As Ionic.Zip.ZipEntry In entries
Console.WriteLine(entry.FileName)
Next
End Using
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| | using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(
@"C:\test.zip", System.Text.Encoding.GetEncoding("shift_jis")))
{
ICollection<Ionic.Zip.ZipEntry> entries = zip.SelectEntries("*.txt");
foreach (Ionic.Zip.ZipEntry entry in entries)
{
Console.WriteLine(entry.FileName);
}
}
|
補足:既存のZIP書庫を開いたのではなく、新しくZipFileを作成した時は、Saveメソッドで保存しなければSelectEntriesメソッドは使用できません。
書庫内のテキストファイルの中身を閲覧する †
前回ZipEntry.Extractメソッドを使って書庫内のファイルを展開する方法を紹介しましたが、このようにファイルに展開するのではなく、内容をStreamとして取得することもできます。それには、ZipEntry.OpenReaderメソッドを使います。
下の例では、ZipEntry.OpenReaderメソッドでCrcCalculatorStreamを取得することで、ZIP書庫内の"readme.txt"の内容を表示しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| | 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")
If entry IsNot Nothing Then
Using ccs As Ionic.Zlib.CrcCalculatorStream = entry.OpenReader()
Using sr As New System.IO.StreamReader( _
ccs, System.Text.Encoding.GetEncoding("shift_jis"))
Console.WriteLine(sr.ReadToEnd())
End Using
End Using
End If
End Using
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| | 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"];
if (entry != null)
{
using (Ionic.Zlib.CrcCalculatorStream ccs = entry.OpenReader())
{
using (System.IO.StreamReader sr = new System.IO.StreamReader(
ccs, System.Text.Encoding.GetEncoding("shift_jis")))
{
Console.WriteLine(sr.ReadToEnd());
}
}
}
}
|
また、ZipEntry.ExtractメソッドでStreamに展開することもできますので、例えばMemoryStreamに展開することもできます。
下の例では、ZipEntry.ExtractメソッドでMemoryStreamにテキストファイルを展開しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| | 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")
If entry IsNot Nothing Then
Using ms As New System.IO.MemoryStream()
entry.Extract(ms)
ms.Position = 0
Using sr As New System.IO.StreamReader( _
ms, System.Text.Encoding.GetEncoding("shift_jis"))
Console.WriteLine(sr.ReadToEnd())
End Using
End Using
End If
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
| | 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"];
if (entry != null)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
entry.Extract(ms);
ms.Position = 0;
using (System.IO.StreamReader sr = new System.IO.StreamReader(
ms, System.Text.Encoding.GetEncoding("shift_jis")))
{
Console.WriteLine(sr.ReadToEnd());
}
}
}
}
|
書庫が正しいかテストする †
ZIP書庫が壊れていないか確かめるには、ZipFile.IsZipFileメソッドを使います。IsZipFileメソッドにZIPファイルのみを指定すると、ZIPメタデータのチェックのみを行います。IsZipFileメソッドの2番目のパラメータにTrueを指定すると、すべてのファイルを展開して確認します。ただしこの場合、パスワードで保護されたファイルがあると、必ずFalseを返します。
1
2
3
4
| | If Ionic.Zip.ZipFile.IsZipFile("C:\test.zip", True) Then
Console.WriteLine("ZIPファイルに問題は見つかりませんでした")
End If
|
1
2
3
4
5
| | if (Ionic.Zip.ZipFile.IsZipFile(@"C:\test.zip", true))
{
Console.WriteLine("ZIPファイルに問題は見つかりませんでした");
}
|
ZipFile.IsZipFile以外にZipFile.CheckZipというメソッドもありますが、これはZIP書庫内のディレクトリに問題がないか調べるもののようです。CheckZipメソッドは問題が見つかれば修正するように指定することもできますし、FixZipDirectoryメソッドで修正することもできます。なおCheckZipとFixZipDirectoryメソッドは、ReducedバージョンのDotNetZipでは使用できません。
既存の書庫にファイルを追加する †
既存の書庫にファイルを追加するには、ZipFile.ReadメソッドでZipFileオブジェクトを作成し、そのZipFileオブジェクトにAddFileメソッドなど(前々号で説明しています)でエントリを追加し、Saveメソッドで保存します。
AddFileメソッドでファイルを追加したときは、既存の書庫に同名のファイルが存在すると、例外がスローされます。もし同名のファイルがあったとしても例外をスローさせずに上書きするならば、AddFileメソッドではなく、UpdateFileメソッドを使用します。
下の例では、UpdateFileメソッドを使って書庫にファイルを追加しています。
1
2
3
4
5
6
7
| | Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read("C:\test.zip")
zip.UpdateFile("C:\readme.txt")
zip.Save()
End Using
|
1
2
3
4
5
6
7
8
| | using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(@"C:\test.zip"))
{
zip.UpdateFile(@"C:\readme.txt");
zip.Save();
}
|
既存の書庫の更新に日本語は使えない? †
実は上のコードにはごまかしがありました。ZipFile.Readメソッドで書庫を開くとき、Encodingを指定しませんでした。私が試した限りでは、EncodingにShift JISを指定して書庫を開き、Saveメソッドで保存すると、書庫が壊れてしまいました。*1また、EncodingをShift JISとして作成したZIP書庫は、上のコードのようにEncodingを指定しないで開いてから更新しても書庫が壊れました。つまり、一般のアーカイバで作成した書庫もこの方法で更新すると壊れると思われます。その上、書庫内に日本語のエントリ名が存在すると、その書庫がUseUnicodeAsNecessaryプロパティをTrueにして作成されたものだとしても、更新すると書庫が壊れました。
つまり、日本語にエントリ名を一切使わず、Encodingを指定しないで作成したZIP書庫だけこの方法で更新できると考えて良さそうです。そのため、現時点では、実用性は極めて低いといえます。
この問題は、以下に紹介する例でも同様に存在します。
書庫から指定したエントリを削除する †
書庫から一つのエントリを削除するには、ZipFile.RemoveEntryメソッドを使います。RemoveEntryメソッドに削除したいエントリ名か、ZipEntryオブジェクトを渡せば、削除できます。
複数のエントリを削除するには、RemoveSelectedEntriesメソッドを使うと便利です。RemoveSelectedEntriesメソッドでは、前々回紹介したAddSelectedFilesメソッドのselectionCriteriaパラメータの書式を使用して削除するファイルを選択できます。
以下の例では、これらのメソッドを使って書庫内のファイルを削除しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| | Using zip As Ionic.Zip.ZipFile = Ionic.Zip.ZipFile.Read("C:\test.zip")
Dim entry As Ionic.Zip.ZipEntry = zip("readme.txt")
If entry IsNot Nothing Then
zip.RemoveEntry(entry)
End If
Dim removeName As String = "readme2.txt"
If zip.EntryFileNames.Contains(removeName) Then
zip.RemoveEntry(removeName)
End If
zip.RemoveSelectedEntries("*.doc")
zip.Save()
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
| | using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(@"C:\test.zip"))
{
Ionic.Zip.ZipEntry entry = zip["readme.txt"];
if (entry != null)
{
zip.RemoveEntry(entry);
}
string removeName = "readme2.txt";
if (zip.EntryFileNames.Contains(removeName))
{
zip.RemoveEntry(removeName);
}
zip.RemoveSelectedEntries("*.doc");
zip.Save();
}
|
コメント †
- パスワード付き書庫のテストはどうすればいいのですか? -- TERRA