ここでは、J#のライブラリであるvjslib.dllを使用して、C#やVB.NETでZIP書庫の作成(圧縮)、展開(解凍)、閲覧を行う方法を紹介します。
なお、.NET FrameworkでZIP書庫を扱う方法は、これ以外にも、以下の記事で説明しているような方法もあります。
C#、VB.NETには一般的なZip書庫を扱う方法が用意されていませんが、J#にはvjslib.dllというライブラリがあり、この中のjava.util.zip名前空間にあるクラスを使うことにより、Zipを扱うことが出来ます。
なおこの方法は、「Using the Zip Classes in the J# Class Libraries to Compress Files and Data with C#」で詳しく紹介されています。
もしvjslib.dllがインストールされていないならば、まずMicrosoft Visual J# 再頒布可能パッケージをインストールしてください。
以下に具体的なコードを示しますが、必ずvjslib.dllを参照に加えてください。また、後ほど述べますが、.NET Framework 1.1以前では多くの問題が確認されていますので、ご注意ください。
まずはZip書庫内のファイル(エントリ)の情報を列挙するコードです。
'開くZIPファイルの設定 Dim zipPath As String = "C:\test.zip" '読み込む Dim fis As New java.io.FileInputStream(zipPath) Dim zis As New java.util.zip.ZipInputStream(fis) 'ZIP内のファイル情報を取得 While True Dim ze As java.util.zip.ZipEntry = zis.getNextEntry() If (ze Is Nothing) Then Exit While End If If Not ze.isDirectory() Then '情報を表示する Console.WriteLine("ファイル名 : {0}", ze.getName()) Console.WriteLine("サイズ : {0} bytes", ze.getSize()) Console.WriteLine("圧縮サイズ : {0} bytes", _ ze.getCompressedSize()) Console.WriteLine("CRC : {0:X}", ze.getCrc()) Dim [date] As New java.util.Date(ze.getTime()) Console.WriteLine("日時 : {0}", [date].ToString()) Console.WriteLine() End If End While '閉じる zis.close() fis.close()
//開くZIPファイルの設定 string zipPath = "C:\\test.zip"; //読み込む java.io.FileInputStream fis = new java.io.FileInputStream(zipPath); java.util.zip.ZipInputStream zis = new java.util.zip.ZipInputStream(fis); //ZIP内のファイル情報を取得 java.util.zip.ZipEntry ze; while ((ze = zis.getNextEntry()) != null) { if (!ze.isDirectory()) { //情報を表示する Console.WriteLine("ファイル名 : {0}", ze.getName()); Console.WriteLine("サイズ : {0} bytes", ze.getSize()); Console.WriteLine("圧縮サイズ : {0} bytes", ze.getCompressedSize()); Console.WriteLine("CRC : {0:X}", ze.getCrc()); java.util.Date date = new java.util.Date(ze.getTime()); Console.WriteLine("日時 : {0}", date.ToString()); Console.WriteLine(); } } //閉じる zis.close(); fis.close();
次はZip書庫内のファイルを展開するコードです。ここでは書庫内のすべてのファイルを展開しています。
'展開するZIPファイルの設定 Dim zipPath As String = "C:\test.zip" '展開先のフォルダの設定 Dim extractDir As String = "C:\temp" '読み込む Dim fis As New java.io.FileInputStream(zipPath) Dim zis As New java.util.zip.ZipInputStream(fis) 'ZIP内のファイル情報を取得 While True Dim ze As java.util.zip.ZipEntry = zis.getNextEntry() If ze Is Nothing Then Exit While End If If Not ze.isDirectory() Then 'ファイル名 Dim fileName As String = _ System.IO.Path.GetFileName(ze.getName()) '展開先のフォルダ Dim destDir As String = System.IO.Path.Combine( _ extractDir, System.IO.Path.GetDirectoryName(ze.getName())) System.IO.Directory.CreateDirectory(destDir) '展開先のパス Dim destPath As String = _ System.IO.Path.Combine(destDir, fileName) 'FileOutputStreamの作成 Dim fos As New java.io.FileOutputStream(destPath) '書込み Dim buffer(8191) As System.SByte While True Dim len As Integer = zis.read(buffer, 0, buffer.Length) If len <= 0 Then Exit While End If fos.write(buffer, 0, len) End While '閉じる fos.close() End If End While zis.close() fis.close()
//展開するZIPファイルの設定 string zipPath = "C:\\test.zip"; //展開先のフォルダの設定 string extractDir = "C:\\temp"; //読み込む java.io.FileInputStream fis = new java.io.FileInputStream(zipPath); java.util.zip.ZipInputStream zis = new java.util.zip.ZipInputStream(fis); //ZIP内のファイル情報を取得 java.util.zip.ZipEntry ze; while ((ze = zis.getNextEntry()) != null) { if (!ze.isDirectory()) { //ファイル名 string fileName = System.IO.Path.GetFileName(ze.getName()); //展開先のフォルダ string destDir = System.IO.Path.Combine( extractDir, System.IO.Path.GetDirectoryName(ze.getName())); System.IO.Directory.CreateDirectory(destDir); //展開先のパス string destPath = System.IO.Path.Combine(destDir, fileName); //FileOutputStreamの作成 java.io.FileOutputStream fos = new java.io.FileOutputStream(destPath); //書込み sbyte[] buffer = new sbyte[8192]; int len; while ((len = zis.read(buffer, 0, buffer.Length)) > 0) { fos.write(buffer, 0, len); } //閉じる fos.close(); } } zis.close(); fis.close();
最後は指定したファイルを圧縮してZip書庫を作成するコードです。
'作成するZIPファイルの設定 Dim zipPath As String = "C:\test.zip" '圧縮するファイルの設定 Dim filePaths As String() = _ { _ "C:\1.bmp", _ "C:\2.bmp" _ } 'ZipOutputStreamの作成 Dim fos As New java.io.FileOutputStream(zipPath) Dim zos As New java.util.zip.ZipOutputStream(fos) 'Zipにファイルを追加する Dim file As String For Each file In filePaths 'ZIPに追加するときのファイル名を決定する Dim f As String = System.IO.Path.GetFileName(file) 'ディレクトリを保持する時は次のようにする 'Dim f As String = file.Remove( _ ' 0, System.IO.Path.GetPathRoot(file).Length) 'f = f.Replace("\", "/") Dim ze As New java.util.zip.ZipEntry(f) ze.setMethod(java.util.zip.ZipEntry.DEFLATED) zos.putNextEntry(ze) 'FileInputStreamの作成 Dim fis As New java.io.FileInputStream(file) '書込み Dim buffer(8191) As System.SByte While True Dim len As Integer = fis.read(buffer, 0, buffer.Length) If len <= 0 Then Exit While End If zos.write(buffer, 0, len) End While '閉じる fis.close() zos.closeEntry() Next file zos.close() fos.close()
//作成するZIPファイルの設定 string zipPath = "C:\\test.zip"; //圧縮するファイルの設定 string[] filePaths = { "C:\\1.bmp", "C:\\2.bmp" }; //ZipOutputStreamの作成 java.io.FileOutputStream fos = new java.io.FileOutputStream(zipPath); java.util.zip.ZipOutputStream zos = new java.util.zip.ZipOutputStream(fos); //Zipにファイルを追加する foreach (string file in filePaths) { //ZIPに追加するときのファイル名を決定する string f = System.IO.Path.GetFileName(file); //ディレクトリを保持する時は次のようにする //string f = file.Remove( // 0, System.IO.Path.GetPathRoot(file).Length); //f = f.Replace("\\","/"); java.util.zip.ZipEntry ze = new java.util.zip.ZipEntry(f); ze.setMethod(java.util.zip.ZipEntry.DEFLATED); zos.putNextEntry(ze); //FileInputStreamの作成 java.io.FileInputStream fis = new java.io.FileInputStream(file); //書込み sbyte[] buffer = new sbyte[8192]; int len; while((len = fis.read(buffer, 0, buffer.Length)) > 0) { zos.write(buffer, 0, len); } //閉じる fis.close(); zos.closeEntry(); } zos.close(); fos.close();
このようにjava.util.zip内のクラスを使うと簡単にZipの扱いができるようになりますが、.NET Framework 1.1以前では非常に多くの問題があることが分かっています(2.0では修正されています)。例えば、上記の方法でパス名に日本語を含むファイルを圧縮するとZip書庫は正常に作成されません。また、ZipEntry.setTimeで日時を指定できません。さらに、先に紹介した「Using the Zip Classes in the J# Class Libraries to Compress Files and Data with C#」のサンプルでは、サイズの大きいバイナリファイルを圧縮すると、エラーが発生します(new ZipFileでエラーが発生しますが、上記のコードではこれを使用していません)。これらのバグについては、次のURL先が参考になります。
#ziplibを使用する方法は「#ziplib(SharpZipLib)を使ってZIP圧縮、展開(解凍)、リスト表示などを行う」に移動しましたので、そちらをご覧ください。
(この記事は、「.NETプログラミング研究 第49号」で紹介したものを基にしています。)