DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

J#のライブラリを使ってZIP圧縮、展開(解凍)、リスト表示を行う

ここでは、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書庫内のファイル(エントリ)の情報を列挙するコードです。

VB.NET
コードを隠すコードを選択
'開く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()
C#
コードを隠すコードを選択
//開く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書庫内のファイルを展開するコードです。ここでは書庫内のすべてのファイルを展開しています。

VB.NET
コードを隠すコードを選択
'展開する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()
C#
コードを隠すコードを選択
//展開する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書庫を作成するコードです。

VB.NET
コードを隠すコードを選択
'作成する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()
C#
コードを隠すコードを選択
//作成する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を使用する方法は「#ziplib(SharpZipLib)を使ってZIP圧縮、展開(解凍)、リスト表示などを行う」に移動しましたので、そちらをご覧ください。

  • 履歴:
  • 2007/1/11 .NET Framework 2.0でjava.util.zipのバグが修正されたことを確認。
  • 2009/11/2 #ziplibを使用する方法をこちらに移動。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • 「???を参照に追加します」の意味が分からないという方は、こちらをご覧ください。
  • Windows Vista以降でUACが有効になっていると、ファイルへの書き込みに失敗する可能性があります。詳しくは、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。