ZIP書庫の作成、閲覧、展開を行う

ZIP書庫の作成、閲覧、展開を行う

ここでは、C#またはVB.NETでZip書庫を扱う(作成、閲覧、展開)方法を紹介します。

J#のクラスを使用する方法

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#」で詳しく紹介されています。

この方法によりZip書庫を扱う具体的なコードを以下に示します。必ずvjslib.dllを参照に加えてください。(後ほど述べますが、現在この方法には多くの問題がありますので、ご注意ください。)

書庫内のファイルを列挙する

まずは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を使用する方法

さらに別の方法として、Zipを扱う有名なライブラリである#ziplibを使う方法があります。(記事を書いている時点でのバージョンは0.81。)#ziplibでは、パスワードの設定を行うこともできます。#ziplibを使ってZipを扱うサンプルを以下に紹介します。

書庫内のファイルを列挙する

まずはZip内のファイルを列挙するコードから。先ほどのjava.util.zipのサンプルと似ていますね。

[VB.NET]
'開くZIPファイルの設定
Dim zipPath As String = "C:/test.zip"

'読み込む
Dim fs As New System.IO.FileStream( _
    zipPath, System.IO.FileMode.Open, _
    System.IO.FileAccess.Read, System.IO.FileShare.Read)
Dim zis As New ICSharpCode.SharpZipLib.Zip.ZipInputStream(fs)

'ZIP内のファイル情報を取得
Dim ze As ICSharpCode.SharpZipLib.Zip.ZipEntry
While True
    ze = zis.GetNextEntry()
    If ze Is Nothing Then
        Exit While
    End If
    If Not ze.IsDirectory Then
        '情報を表示する
        Console.WriteLine("ファイル名 : {0}", ze.Name)
        Console.WriteLine("サイズ : {0} bytes", ze.Size)
        Console.WriteLine("圧縮サイズ : {0} bytes", _
            ze.CompressedSize)
        Console.WriteLine("CRC : {0:X}", ze.Crc)
        Console.WriteLine("日時 : {0}", ze.DateTime)
        Console.WriteLine()
    End If
End While

'閉じる
zis.Close()
fs.Close()
[C#]
//開くZIPファイルの設定
string zipPath = "C://test.zip";

//読み込む
System.IO.FileStream fs = new System.IO.FileStream(
    zipPath, System.IO.FileMode.Open,
    System.IO.FileAccess.Read, System.IO.FileShare.Read);
ICSharpCode.SharpZipLib.Zip.ZipInputStream zis = 
    new ICSharpCode.SharpZipLib.Zip.ZipInputStream(fs);

//ZIP内のファイル情報を取得
ICSharpCode.SharpZipLib.Zip.ZipEntry ze;
while ((ze = zis.GetNextEntry()) != null)
{
    if (!ze.IsDirectory)
    {
        //情報を表示する
        Console.WriteLine("ファイル名 : {0}", ze.Name);
        Console.WriteLine("サイズ : {0} bytes", ze.Size);
        Console.WriteLine("圧縮サイズ : {0} bytes",
            ze.CompressedSize);
        Console.WriteLine("CRC : {0:X}", ze.Crc);
        Console.WriteLine("日時 : {0}", ze.DateTime);
        Console.WriteLine();
    }
}

//閉じる
zis.Close();
fs.Close();
書庫内のファイルを展開する

次はZip書庫内のすべてのファイルを展開するコードです。これもjava.util.zipのサンプルと似ています。

[VB.NET]
'展開するZIPファイルの設定
Dim zipPath As String = "C:/test.zip"
'展開先のフォルダの設定
Dim extractDir As String = "C:/temp"

'読み込む
Dim fs As New System.IO.FileStream( _
    zipPath, System.IO.FileMode.Open, _
    System.IO.FileAccess.Read, System.IO.FileShare.Read)
Dim zis As New ICSharpCode.SharpZipLib.Zip.ZipInputStream(fs)
'パスワードが設定されているとき
'zis.Password = "pass"

'ZIP内のファイル情報を取得
Dim ze As ICSharpCode.SharpZipLib.Zip.ZipEntry
While True
    ze = 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.Name)
        '展開先のフォルダ
        Dim destDir As String = System.IO.Path.Combine( _
            extractDir, System.IO.Path.GetDirectoryName(ze.Name))
        System.IO.Directory.CreateDirectory(destDir)
        '展開先のパス
        Dim destPath As String = _
            System.IO.Path.Combine(destDir, fileName)

        '書込み
        Dim writer As New System.IO.FileStream( _
            destPath, System.IO.FileMode.Create, _
            System.IO.FileAccess.Write, System.IO.FileShare.Write)
        Dim buffer(2047) As Byte
        Dim len As Integer
        While True
            len = zis.Read(buffer, 0, buffer.Length)
            If len <= 0 Then
                Exit While
            End If
            writer.Write(buffer, 0, len)
        End While
        '閉じる
        writer.Close()
    End If
End While

zis.Close()
fs.Close()
[C#]
//展開するZIPファイルの設定
string zipPath = "C://test.zip";
//展開先のフォルダの設定
string extractDir = "C://temp";

//読み込む
System.IO.FileStream fs = new System.IO.FileStream(
    zipPath, System.IO.FileMode.Open,
    System.IO.FileAccess.Read, System.IO.FileShare.Read);
ICSharpCode.SharpZipLib.Zip.ZipInputStream zis = 
    new ICSharpCode.SharpZipLib.Zip.ZipInputStream(fs);
//パスワードが設定されているとき
//zis.Password = "pass";

//ZIP内のファイル情報を取得
ICSharpCode.SharpZipLib.Zip.ZipEntry ze;
while ((ze = zis.GetNextEntry()) != null)
{
    if (!ze.IsDirectory)
    {
        //ファイル名
        string fileName = System.IO.Path.GetFileName(ze.Name);
        //展開先のフォルダ
        string destDir = System.IO.Path.Combine(extractDir,
            System.IO.Path.GetDirectoryName(ze.Name));
        System.IO.Directory.CreateDirectory(destDir);
        //展開先のパス
        string destPath = System.IO.Path.Combine(destDir, fileName);

        //書込み
        System.IO.FileStream writer = new System.IO.FileStream(
            destPath, System.IO.FileMode.Create,
            System.IO.FileAccess.Write,
            System.IO.FileShare.Write);
        byte[] buffer = new byte[2048];
        int len;
        while ((len = zis.Read(buffer, 0, buffer.Length)) > 0)
        {
            writer.Write(buffer, 0, len);
        }
        //閉じる
        writer.Close();
    }
}

zis.Close();
fs.Close();
書庫を作成する

最後にファイルを圧縮してZip書庫を作成するサンプルです。ここではヘッダでエントリの情報を設定していますが、これを省略すると、フッタに書き込まれます。また、パスワードを"pass"に設定しています。

[VB.NET]
'作成するZIPファイルの設定
Dim zipPath As String = "C:/test.zip"
'圧縮するファイルの設定
Dim filePaths As String() = _
    { _
        "C:/1.txt", _
        "D:/2.txt" _
    }

Dim crc As New ICSharpCode.SharpZipLib.Checksums.Crc32

Dim writer As New System.IO.FileStream( _
    zipPath, System.IO.FileMode.Create, _
    System.IO.FileAccess.Write, System.IO.FileShare.Write)
Dim zos As New ICSharpCode.SharpZipLib.Zip.ZipOutputStream(writer)
'圧縮レベルを設定する
zos.SetLevel(6)
'パスワードを設定する
zos.Password = "pass"

'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 ICSharpCode.SharpZipLib.Zip.ZipEntry(f)

    'ヘッダを設定する
    'ファイルを読み込む
    Dim fs As New System.IO.FileStream( _
        file, System.IO.FileMode.Open, _
        System.IO.FileAccess.Read, System.IO.FileShare.Read)
    Dim buffer(fs.Length) As Byte
    fs.Read(buffer, 0, buffer.Length)
    fs.Close()
    'CRCを設定する
    crc.Reset()
    crc.Update(buffer)
    ze.Crc = crc.Value
    'サイズを設定する
    ze.Size = buffer.Length
    '時間を設定する
    ze.DateTime = DateTime.Now

    '新しいエントリの追加を開始
    zos.PutNextEntry(ze)
    '書き込む
    zos.Write(buffer, 0, buffer.Length)
Next file

zos.Close()
writer.Close()
[C#]
//作成するZIPファイルの設定
string zipPath = "C://test.zip";
//圧縮するファイルの設定
string[] filePaths =
    {
        @"C:/test1.txt",
        @"D:/Download/mt.txt"
    };

ICSharpCode.SharpZipLib.Checksums.Crc32 crc =
    new ICSharpCode.SharpZipLib.Checksums.Crc32();

System.IO.FileStream writer = new System.IO.FileStream(
    zipPath, System.IO.FileMode.Create,
    System.IO.FileAccess.Write,
    System.IO.FileShare.Write);
ICSharpCode.SharpZipLib.Zip.ZipOutputStream zos = 
    new ICSharpCode.SharpZipLib.Zip.ZipOutputStream(writer);
//圧縮レベルを設定する
zos.SetLevel(6);
//パスワードを設定する
zos.Password = "pass";

//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("//","/");

    ICSharpCode.SharpZipLib.Zip.ZipEntry ze =
        new ICSharpCode.SharpZipLib.Zip.ZipEntry(f);

    //ヘッダを設定する
    //ファイルを読み込む
    System.IO.FileStream fs = new System.IO.FileStream(
        file,
        System.IO.FileMode.Open,
        System.IO.FileAccess.Read,
        System.IO.FileShare.Read);
    byte[] buffer = new byte[fs.Length];
    fs.Read(buffer, 0, buffer.Length);
    fs.Close();
    //CRCを設定する
    crc.Reset();
    crc.Update(buffer);
    ze.Crc = crc.Value;
    //サイズを設定する
    ze.Size = buffer.Length;
    //時間を設定する
    ze.DateTime = DateTime.Now;

    //新しいエントリの追加を開始
    zos.PutNextEntry(ze);
    //書き込む
    zos.Write(buffer, 0, buffer.Length);
}

zos.Close();
writer.Close();

アンマネージDLLを使用する方法

これ以外の方法では、アンマネージDLLを使う方法があります。これに関しては、「遅延バインディングによりアンマネージDLL関数を呼び出す」をご覧ください。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值