20231


オブジェクトを`ObjectOutputStream`で書き出して`JarOutputStream`でJarファイルにて、  
そのJarファイルを`JarInputStream`で読み込んで`ObjectInputStream`のコンストラクターを呼び出したところで例外が飛んできます…  
以下のようなことをしていますが、どうにも成功しません。

## 出力

①オブジェクトを`ObjectOutputStream`で一時出力

②出力された一時ファイルを`ObjectInputStream`で読み込む

③ストリームからbyte[]を取得

④`JarOutputStream`で書き出し

圧縮しなければ問題ないので、①と②に問題はないかと…

具体的には

[code]

    //一時ファイル書き出しは省略
    //tempFileは書き出した場所とおなじFileクラス。
    
    //例外処理省略
    
    byte[] objectData = ObjectInput(tempFile);//読み込む
    
    jos = new JarOutputStream(new FileOutputStream(new File("test.jar")));
    jos.setMethod(JarOutputStream.STORED); //無圧縮を指定
    
    JarEntry entry = new JarEntry("data");  //格納ファイル名
    
    entry.setSize(objectData.length);   //データサイズをセット
    
    CRC32 crc = new CRC32();
    crc.update(objectData);
    entry.setCrc(crc.getValue());   //CRCをセット
    
    jos.putNextEntry(entry);
    jos.write(objectData);
    
    /* 条件によって複数ファイル格納 */
    //テスト時はファイルいっこだけで試してみました。
    
    jos.flush();
    
[/code]

最初の`ObjectInput`はこんな感じになってます

[code]

    public static byte[] ObjectInput(File file) throws IOException{
    
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
            byte[] data = new byte[(int) file.length()];
    
            ois.read(data);
    
            ois.close();
            return data;
        }
    
[/code]

出力自体は成功してるように思います。  
出力されたファイル内のtestが格納されており、  
ファイルサイズがもとの一時ファイルと一致しているので…

CRCがメタデータなのか、ファイルに含まれるのか、  
よくわからないのでそこが原因かもしれませんが…

## 読み込み

①指定されたファイル(ここでは上記したファイルを読み込む)を`JarInputStream`で読み込む

②`.getNextJarEntry()`を使ってJarEntryを取得

(ファイルは正しいものとして進めさせてください。実際圧縮しなければ読み込めました。)

③`FileOutputStream`で一時出力

④一時ファイルを`ObjectInputStream`で読み込む←ここで例外が飛ぶ

⑤オブジェクトを`.readObject()`で取得

例外の内容としては、  
`java.io.StreamCorruptedException: invalid stream header: 00000000`

もし圧縮すると、  
`java.io.StreamCorruptedException: invalid stream header: 504B0304`

という例外が同じところで飛んできます。

あとなんかハイライトされなんですけど、私が悪いんでしょうか(^_^;)

* * *

バイト列を用いることで解決しました。  
失礼しました。


CC BY-SA 3.0
2015-12-20T02:49:40.070
20197
2015-12-22T13:38:54.327
2015-12-20T14:01:59.430
33
13553
question
java java8
Javaで圧縮したファイルを解凍してオブジェクトとして読み込む

[code]

    byte[] objectData = ObjectInput(tempFile);//読み込む
    
[/code]

この部分の`ObjectInput`メソッドの戻り値`objectData`を、例えば次のようなメソッドで出力してみるとわかりますが、想定されたように読み込まれていません。  
(おそらく全て`0`で出力されると思います。)

[code]

    private static void print(byte[] objectData) {
        for(byte c : objectData) {
            System.out.format("%d ", c);
        }
    }
    
[/code]

つまり`ObjectInput`メソッドの実装に問題があります(ので、「圧縮しなければ問題ない」というのは何か勘違いをされているかと)。

ここでやりたいのは、ファイルをバイト列として読み込みたいだけなので、`ObjectInputStream`ではなく`FileInputStream`が適切だと思います。  
したがって、`ObjectInput`メソッドは次のように実装することになります。

[code]

    public static byte[] ObjectInput(File file) throws IOException {
    
        FileInputStream fis = new FileInputStream(file);
        byte[] data = new byte[(int) file.length()];
    
        fis.read(data);
    
        fis.close();
        return data;
    }
    
[/code]

* * *

「バイト列を用いることで解決しました」というのがよく理解できなかったのですが、[こちら](https://teratail.com/questions/23013)の書き込みから想像するに、一時ファイルの作成をやめた(`ObjectInput`を使用しなくなった)ということですかね。  
確かにこの処理自体不要です。

* * *

そんなわけで経緯をよく理解できていないのですが、オブジェクトをjarファイルに出力したいのであれば、あまり深く考えずに、そういうストリームを構築すれば良いのでは無いかと思います。

オブジェクトを書き出したいので`ObjectOutputStream`を使う、それをjar圧縮して最終的にファイルに、となるとそれぞれ`JarOutputStream`,
`FileOutputStream`なのでこれらをつなげて

[code]

    ObjectOutputStream os = new ObjectOutputStream(new JarOutputStream(new FileOutputStream(file)));
    
[/code]

…としたいところですが、このままですと`JarOutputStream`の作法に従っていないというエラーが出ますのでその部分を修正します。  
そうすると以下の`compress`メソッドのような感じになるかと思います。  
(また、本件タイトルに沿った「Javaで圧縮したファイルを解凍してオブジェクトとして読み込む」メソッドが`decompress`です。)

[code]

    void compress(File jar, Asset target) throws IOException {
        try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(jar))) {
            JarEntry ze = new JarEntry("asset");
            jos.putNextEntry(ze);
            try (ObjectOutputStream os = new ObjectOutputStream(jos)) {
                os.writeObject(target);
            }
        }
    }
    
    Asset decompress(File jar) throws IOException, ClassNotFoundException {
        try (JarInputStream jis = new JarInputStream(new FileInputStream(jar))) {
            jis.getNextJarEntry();
            try (ObjectInputStream is = new ObjectInputStream(jis)) {
                return (Asset) is.readObject();
            }
        }
    }
    
[/code]

上記は無圧縮jarではないですが、敢えて圧縮しないのであればわざわざ`JarOutputStream`を使わず直接`FileOutputStream`を使うのが楽だと思います。

全体はここに挿入するには長くなってしまったので[外部サイト(gist)](https://gist.github.com/yukihane/b14133de6f40d8fb8750)に置いています。


CC BY-SA 3.0
2015-12-20T17:02:24.610
20231
2015-12-22T13:38:54.327
2015-12-22T13:38:54.327
2808
2808
20197
answer