- PR -

ZIPファイル圧縮について

投稿者投稿内容
えれ
会議室デビュー日: 2004/06/18
投稿数: 10
投稿日時: 2004-06-18 19:01
初投稿させて頂きます

SDK 1.4.2 を使用しています。
java.util.zip を用いてzip圧縮を以下のソースで
やっていますが、2つの問題が出ています。

1つは、圧縮したファイル名が化けてしまうこと
2つめは、サブフォルダがある状態でZIP化すると
フォルダ毎圧縮されてしまう

この2つです。

前者は、自力の調査結果によるとUTF-8固定で
ZipOutstreamがファイル名の変換を行っているので
無理ではないかとの結論にいたっています。後者は
いろいろ試したのですが、結論にすら至れていないので
皆様のお知恵をお貸し頂ければと思い投稿させて頂きました。


以下ソースです

//両方引数とも フルパスが入っています。
public void compressFile(File file, File zipfile)
throws FileNotFoundException,ZipException, IOException
{
//-- 変数初期化
ByteArrayOutputStream baos = null;
BufferedOutputStream bos = null;
FileOutputStream fos = null;
ZipOutputStream zos = null;
ZipEntry zent = null;

try
{
// 圧縮ファイル名を取得
String zipFilename = zipfile.getPath();

// 圧縮前後サイズ及びCRCを取得  
baos = new ByteArrayOutputStream();
zos = new ZipOutputStream(baos);

ArrayList al = new ArrayList();

// バイト配列に元のファイルを読み込む
byte[] buf = getFileBytes(file.getPath());

zent = new ZipEntry(file.getPath());
al.add(zent); //ZipEntryを格納しておく
zos.putNextEntry(zent);
zos.write(buf, 0, buf.length);
//ZipOutputStreamのcloseEntryを呼び出した時点で
//zipEntryに 圧縮前サイズ・圧縮後サイズ・CRC情報を取得できる
zos.closeEntry();

//Buffer/ZipFile 例外処理
try{zos.close(); }catch (Exception e){}
try{baos.close();}catch (Exception e){}

// 実圧縮
baos = new ByteArrayOutputStream();
zos = new ZipOutputStream(baos);
// バイト配列に元のファイルを読み込む
buf = getFileBytes(file.getPath());

zent = (ZipEntry)al.get(0);
zos.putNextEntry(zent);
zos.write(buf, 0, buf.length);
zos.closeEntry();

zos.finish();

// 圧縮データを取り出す
byte[] bufResult = baos.toByteArray();

// 書き込む
fos = new FileOutputStream(zipFilename);
bos = new BufferedOutputStream(fos);
bos.write(bufResult, 0, bufResult.length);
// 実圧縮
}

//ファイル存在 例外
catch (FileNotFoundException e){throw e;}
//ZIP処理  例外
catch (ZipException e){ throw e;}
//入出力    例外
catch (IOException e) { throw e;}




// ファイル中のデータをbyte配列にして返す
private byte[] getFileBytes(String filename)
{
//各種変数
File file = null;
FileInputStream fis = null;
BufferedInputStream bis = null;

try
{
file = new File(filename);
int len = (int)file.length();
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis, len);

byte buf[] = new byte[len];
bis.read(buf, 0, len);
return buf;
}
catch (IOException e)
{
}
finally
{
try
{
if (bis != null)
{
bis.close();
}
}
catch (Exception e)
{
}
try
{
if (fis != null)
{
fis.close();
}
}
catch (Exception e)
{
}
}


丸投げ状態で申し訳ありませんがよろしくお願いいたします。
いっきゅう
大ベテラン
会議室デビュー日: 2004/04/04
投稿数: 153
お住まい・勤務地: 兵庫
投稿日時: 2004-06-20 17:59
> 1つは、圧縮したファイル名が化けてしまうこと

これはUTF-8で文字を格納するのがデフォルトで変更が聞きませんね確かに、
別途ZIP圧縮のコマンドを呼ぶプロセスを呼び出すのが
簡単に対応できるとおもいます。

> 2つめは、サブフォルダがある状態でZIP化すると
> フォルダ毎圧縮されてしまう

これはZipEntryにフルパスを格納しているからです。
ファイル名を指定してやればサブフォルダは作成されません。

後、ざっとソースを見て思ったんですが用途によりますが
ファイルのデータを全てメモリ内に確保していますが、
OutofMemoryErrorの原因になりかねないので
修正したほうがいいと思います。
coasm
大ベテラン
会議室デビュー日: 2001/11/26
投稿数: 237
投稿日時: 2004-06-20 22:04
> 1つは、圧縮したファイル名が化けてしまうこと

これはFAQなのですが、
java.util.zip.ZipOutputStream の代りに、org.apache.tools.zip.ZipOutputStream を
使うことでこの問題を回避できます。

apacheの方には、ZipOutputStream#setEncoding(String encoding) というメソッドがあって、
ファイル名やコメントのエンコーディングを指定できるようになっています。
http://antxtras.org/apis/thirdparty/ant/manual/api/org/apache/tools/zip/ZipOutputStream.html

jakarta.commons ではなく、antの一部として配布されているのが盲点ですが、
ライセンス条件は普通にapacheだったように記憶しています。

いっきゅう
大ベテラン
会議室デビュー日: 2004/04/04
投稿数: 153
お住まい・勤務地: 兵庫
投稿日時: 2004-06-21 11:07
coasmさんのご紹介を参考にファイル名の文字化けを回避することが出来ました。
今後の参考にさせて頂きます。

後、ライセンスの適応はソースコードに
Apache License Version 2.0が適応されていることを確認しました。

引用:

coasmさんの書き込み (2004-06-20 22:04) より:
> 1つは、圧縮したファイル名が化けてしまうこと

これはFAQなのですが、
java.util.zip.ZipOutputStream の代りに、org.apache.tools.zip.ZipOutputStream を
使うことでこの問題を回避できます。

apacheの方には、ZipOutputStream#setEncoding(String encoding) というメソッドがあって、
ファイル名やコメントのエンコーディングを指定できるようになっています。
http://antxtras.org/apis/thirdparty/ant/manual/api/org/apache/tools/zip/ZipOutputStream.html

jakarta.commons ではなく、antの一部として配布されているのが盲点ですが、
ライセンス条件は普通にapacheだったように記憶しています。



えれ
会議室デビュー日: 2004/06/18
投稿数: 10
投稿日時: 2004-06-21 13:21
[quote]
> これはFAQなのですが、
> java.util.zip.ZipOutputStream の代りに、org.apache.tools.zip.ZipOutputStream を
> 使うことでこの問題を回避できます。

確かに、そのような方法で改善できそうなのですが
現行ソースでは、パッケージを差し替えますと圧縮が出来ないのと
フォルダに対応が出来ないみたいです。現在調査を続行はしています。

> これはUTF-8で文字を格納するのがデフォルトで変更が聞きませんね確かに、
> 別途ZIP圧縮のコマンドを呼ぶプロセスを呼び出すのが
> 簡単に対応できるとおもいます。

やはり、そうでしたか!ありがとうございました。

[/quote]
coasm
いっきゅうさん

どうも、ありがとうございます。
現在、org.apache.tools.zipへの差し替え作業を行っていますので
私の方では結果が出ていません。
ちなみに、差し替えで発生した問題は以下のとおりです。

1.単純に Setencodingメソッドを追加すると日本語名のファイルが
圧縮できない。

2.差し替えただけだと、解凍時に(Lahapulus)エラーが発生して
しまいます。

もう少し自力で探ってみたいと思います。
いっきゅう
大ベテラン
会議室デビュー日: 2004/04/04
投稿数: 153
お住まい・勤務地: 兵庫
投稿日時: 2004-06-21 14:32
> 現行ソースでは、パッケージを差し替えますと圧縮が出来ないのと
> フォルダに対応が出来ないみたいです。現在調査を続行はしています。

私が確認したところフォルダの圧縮も
new ZipEntry(filename + "/")
という感じで最後にセパレートを入れれば可能でした。

> 現在、org.apache.tools.zipへの差し替え作業を行っていますので
> 私の方では結果が出ていません。

import java.util.zip.*;
を外して
import org.apache.tools.zip.*;
に変更するだけで何も問題発生はしないと思います。

> ちなみに、差し替えで発生した問題は以下のとおりです。
>
> 1.単純に Setencodingメソッドを追加すると日本語名のファイルが
> 圧縮できない。
Windowsで使っているならばSetEncodingするまでもないです。
システムのCharsetが使用されます。

>
> 2.差し替えただけだと解凍時に(Lahapulus)エラーが発生してしまいます。

私も解凍はされますが、エラーは出ています。

以上。

後、当方で確認した環境は
WindowsXP SP1
j2SDK1.4.2_04
Apache Ant 1.6.1(org.apache.tools.zipパッケージ部分のみ)
coasm
大ベテラン
会議室デビュー日: 2001/11/26
投稿数: 237
投稿日時: 2004-06-21 14:39
書き忘れていましたが、java.util.zip.ZipInputStream は UTF-8固定になっているので、
シフトJISでエンコードした日本語ファイル名を解凍することはできません。
また、org.apache.tools.zip には ZipInputStream クラスは存在しません。

つまり、java.util.zip.ZipInputStream を使って日本語ファイル名を(シフトJISで)
含んだzipファイルを作成することはできますが、Javaのプログラムでそれを解凍する手段は
ありません。

解凍に関しては、外部プログラム(upzip.exeとか)を起動するしかないのではないか、と。
いっきゅう
大ベテラン
会議室デビュー日: 2004/04/04
投稿数: 153
お住まい・勤務地: 兵庫
投稿日時: 2004-06-21 15:03
> 書き忘れていましたが、java.util.zip.ZipInputStream は UTF-8固定に
> なっているので、 シフトJISでエンコードした日本語ファイル名を
> 解凍することはできません。
> また、org.apache.tools.zip には ZipInputStream クラスは存在しません。
> つまり、java.util.zip.ZipInputStream を使って日本語ファイル名を
>(シフトJISで)含んだzipファイルを作成することはできますが、
> Javaのプログラムでそれを解凍する手段はありません

ありますよ、

org.apache.tools.zip.ZipFileクラスに
方法はZipEntryのEnumeration取り出して
ZipFileにZipEntryを引数にしてファイル毎の解凍されたInputStreamがとりだせます。


[ メッセージ編集済み 編集者: いっきゅう 編集日時 2004-06-21 15:05 ]

スキルアップ/キャリアアップ(JOB@IT)