SharpZlibを使って圧縮/解凍
ファイルの圧縮/解凍をしたいという要求があったので、SharpZlibを使って実験してみました(・∀・)
ZIP圧縮についてはJ#のランタイムにjava.util.zipとかもあるんですが、これは色々と問題もあるらしいということで(´・ω・`)
で、.NETで圧縮/解凍といえばSharpZlibだと思ったので使ってみることにしました。
ちなみに、それ以外の選択肢となるとZlibラッパーを作るとかでしょうか?
とか言っていたら、こんなんのも見つけたり。
http://www.componentace.com/ZLIB.NET
で、特定フォルダ下にあるファイルの圧縮と、圧縮したファイルの解凍ができれば良いということなので、以下のようなサンプルを作ってみました。
まず、特定フォルダ下にあるファイル一覧の取得処理を作っておきます。
再帰的にファイル一覧をArrayListに入れる処理ですね。
private static void ListupFiles(string path, ArrayList list) { string[] subdirs = Directory.GetDirectories( path ); foreach( string subdir in subdirs) { ListupFiles( subdir, list ); } string[] files = Directory.GetFiles( path ); foreach( string file in files ) { list.Add( file ); } }
で、取得したファイル一覧のZIPファイルを作成する処理はこんなんで良いようです。
public static void Zip(string zipfile, string baseFolder) { ArrayList list = new ArrayList(); ListupFiles( baseFolder, list ); Zip( zipfile, baseFolder, (string[])list.ToArray( typeof(string) ) ); } public static void Zip(string zipfile, string baseFolder, string[] files) { Crc32 crc = new Crc32(); string baseFoler = Path.GetFullPath( baseFolder ); using( FileStream fs = new FileStream( zipfile, FileMode.Create, FileAccess.Write, FileShare.Write ) ) using( ZipOutputStream zos = new ZipOutputStream( fs ) ) { zos.SetLevel( 6 ); foreach( string file in files ) { string filename = Path.GetFullPath( file ); if ( filename.StartsWith( baseFoler ) == true ) { filename = filename.Substring( baseFoler.Length ); } else { filename = Path.GetFileName( file ); } ZipEntry ze = new ZipEntry( filename ); using( FileStream fis = new FileStream( file, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { byte[] buffer = new byte[ fis.Length ]; fis.Read( buffer, 0, buffer.Length ); fis.Close(); 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(); fs.Close(); } }
ZIPファイル中のファイル名と、物理的なファイル名の使い分けが注意点でしょうか?(・∀・)
で、解凍処理はこんな感じで良いようです。
public static void Unzip(string zipfile, string extractPath) { extractPath = Path.GetFullPath( extractPath ); using( FileStream fs = new FileStream( zipfile, FileMode.Open, FileAccess.Read, FileShare.Read ) ) using( ZipInputStream zis = new ZipInputStream( fs ) ) { ZipEntry ze; while( ( ze = zis.GetNextEntry() ) != null ) { if ( ze.IsDirectory == true ) { continue; } string filename = Path.GetFileName( ze.Name ); string dstPath = extractPath + Path.GetDirectoryName( ze.Name ); Directory.CreateDirectory( dstPath ); string dstFile = Path.Combine( dstPath, filename ); using( FileStream fos = new FileStream( dstFile, FileMode.Create, FileAccess.Write, FileShare.Write ) ) { byte[] buffer = new byte[ 4096 ]; int length; while( ( length = zis.Read( buffer, 0, buffer.Length ) ) > 0 ) { fos.Write( buffer, 0, length ); } fos.Close(); } } zis.Close(); fs.Close(); } }
ファイルの展開先については、指定されたフォルダにZIP中のパスを取得して、Directory.CreateDirectory()してそこに解凍しています。