質問: (char)fisi; System.out.println(c +"を読込み、コピーします"); bos.write(c); fisi=fis.read(); } System.out.println("成功しました"); bos.flush(); bos.close(); fis.close(); }catch(IOException e) { System.out.println("失敗しました"); try { if(fis != null) fis.close(); if(gzos != null) gzos.close(); }catch(IOException e2) {} } } } ``` プログラミング初心者なので、お手数ですができるだけかみ砕いたご説明をいただけると助かります。
回答: 問題は次の点にあります。 まずは、`bos` の `write` メソッドを使っている点です。 ここは、 `gzos` の `write` メソッドを使いましょう。 そうしないと、`GZIPOutputStream` が基底クラスの `write` メソッドをオーバーライドして実現しようとした処理が実行されず、期待通りの出力を得られなくなります。 ついでに言うと、`System.out.println` で読み込んだ値を `char` 型にキャストして表示していますが、`FileInputStream` クラスの `read` メソッドはファイルから1バイトずつ読み込みますので、複数バイトで表現される文字(漢字など)の場合、1バイト読むごとに `char` にキャストしてもまともな文字としては表示されません。1バイトで表現される文字であれば結果的にうまくいくのですが、論理的には考慮がかけたコードになっていると言えます。 `char` 型の `c` を `gzos` の `write` メソッドで書き出しても結果的に期待通りに動きますが、不必要なキャストはやめて、 `gzos.write(fisi);` とするので十分です。 出力するファイル名の拡張子には `.gz` をつけると良いでしょう。 展開ツールなどがファイルの圧縮形式を GZIP として扱ってくれます。 `.gz` をつけるときは`"~FileCopy2.txt.gz"` とすると、展開後に `~FileCopy2.txt` というファイル名になります。 なお、出来上がったファイルをテキストエディター等で、圧縮したまま開いてもまともに表示されないのでご注意を。 最後に、 正常に処理できた時には、`gzos.close()` を実行しましょう。 そうすることで `bos` の `flush` と `close` は不要というよりも、むしろ実行すべきではないと考えた方が良いです。 `GZIPOutputStream` の親クラス `DeflaterOutputStream` の `close` メソッドの Javadoc を見ると次のように書いてありますので、 `gzos` に対して `flush` は実行しなくて良いです。 (`GZIPOutputStream` は `close` メソッドをオーバーライド指定ないので、メソッドの使用を確認するには親クラスを見る必要があります。) > > public void close() > > throws IOException > > 残りの圧縮データを出力ストリームに書き込み、ストリームを閉じます。 > > >