2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Windows + JavaのUNICODE ZIPへの圧縮対応状況をざっと確認

Last updated at Posted at 2020-07-25

概要

マルチ プラットフォームに向け仕様改定があったはずなのに、未だに思ったほど普及が進んでいない様に思える、UNICODE ZIP。コロナの禍中で在宅ワークも増えて、ZIPファイルでの情報交換がより増えているはずで、UNICODE ZIPの必要性はより高まっていると思う。

ふとmacOS周りの事情やマルチプラット フォームのアーカイバが気になっり、
そもそも JavaのUNICODE ZIPの対応状況はどうなのだろう? と思い、軽く調べてみた。

結論

  • Java 7 以降はUNICODE ZIPの圧縮に対応している。
    • JDK 6 で ビルドしたプログラムでもJRE 7 以降で実行すれば、UNICODE ZIPが作れる。
      targetオプションなどで 7以上を対象にするのが望ましそう
  • Java 6 以前は非対応。Apach Commons Compressで対応可能。
  • WEBアプリでのZIPの文字化け対策は、適切にUNICODE ZIPをしっかり使うこと。
    • WEBアプリはマルチ プラットフォームがそもそもの本懐。
    • WEBアプリが今更MS932で圧縮なんてしてはいけない。
      ( 馬鹿げている と言っても過言ではないくらい、随分と昔に対応されているため)
    • UNICODE ZIPに対応していない、旧時代の圧縮解凍ソフトを使うのを辞める。
      • 解凍に対応:Windows Explorer, 7zip, Explzh, ...
      • 解凍に非対応:Lhasa, Lhaplus

※ 窓の杜さん、マジでいつまでもサイトTOPのオススメ ソフトに、
UNICODE ZIPに対応していないLhaplusを掲載するの辞めてください。。。
せっかくWindows 8からExplorerがUNICODE ZIPに対応しているのに、完全にスポイルされ続しているので。。。

検証

確認環境

  • Windows 10
  • ビルド
    • JDK 6, 7,
    • Open JDK 7, 14
  • 実行
    • JRE 6, 7, 8
    • Open JDK 7, 14

確認方法

  • Javaで圧縮するサンプル プログラムを作成。
  • 各JDKに同梱されているJREなどでそれぞれ実行し、ファイル名に日本語を含むサンプル ファイルを圧縮。
  • 7zipで開き、特性カラムを確認。
    • UNICODEの記載がある
      ⇒ Language encoding flag (EFS) が立っている
      ⇒ 正常なUNICODE ZIP
    • UNICODEの記載がない
      ⇒ Language encoding flag (EFS) が立っていない
      ⇒ 旧来のZIP
      (OSの文字コードに依存するため、圧縮時と解凍時のOSのシステム文字コードが一致している必要がある)

7zipで確認.png

参考資料

圧縮結果表

閾値が割と見えたので、総当たりは行っていない。
(JDKを揃えるのが大変なので)

ビルド
(javac)
実行
(java)
Language
encoding
flag
(EFS)
備考
JDK 6 JRE 6 なし NG
UTF-8のOSで圧縮しただけのZIP状態
JDK 6 JRE 7 あり OK
JDK 6 JRE 8 あり OK
JDK 6 Open JDK 7 あり OK
JDK 6 Open JDK 14 あり OK
JDK 7 JRE 6 - 実行不可
JDK 7 JRE 7 あり OK
JDK 7 JRE 8 あり OK
JDK 7 Open JDK 7 あり OK
JDK 7 Open JDK 14 あり OK
Open JDK 7 JRE 6 - 実行不可
Open JDK 7 JRE 7 あり OK
Open JDK 7 JRE 8 あり OK
Open JDK 7 Open JDK 7 あり OK
Open JDK 7 Open JDK 14 あり OK
Open JDK 14 JRE 6 - 実行不可
Open JDK 14 JRE 7 - 実行不可
Open JDK 14 JRE 8 - 実行不可
Open JDK 14 Open JDK 7 - 実行不可
Open JDK 14 Open JDK 14 あり OK

JavaはASCII文字のファイル名の場合でも、EFSを付ける様子。
7Zipは非ASCII文字以外を含む場合のみのため、ちょっとした違い。
ただし、UNICODE ZIPはUTF-8を使用しており、ASCII部分には互換があるため、EFSの有無はあまり影響は無い。

圧縮結果表 (Linux)

ちょうど手元にUbuntu 20をインストールした仮想マシンがあったので、ついうっかりLinux版OpenJDKも軽く試してみた。

ビルド
(javac)
実行
(java)
Language
encoding
flag
(EFS)
備考
Windows
JDK 6
Linux
Open JDK 7
あり OK
Windows
JDK 6
Linux
Open JDK 8
あり OK
Windows
JDK 6
Linux
Open JDK 14
あり OK
Windows
JDK 7
Linux
Open JDK 7
あり OK
Windows
JDK 7
Linux
Open JDK 8
あり OK
Windows
JDK 7
Linux
Open JDK 14
あり OK
Windows
Open JDK 14
Linux
Open JDK 7
あり OK
Windows
Open JDK 14
Linux
Open JDK 8
あり OK
Windows
Open JDK 14
Linux
Open JDK 14
あり OK
Linux
Open JDK 7
Windows
JRE 6
- 実行不可
Linux
Open JDK 7
Windows
JRE 7
あり OK
Linux
Open JDK 7
Windows
JRE 8
あり OK
Linux
Open JDK 7
Windows
Open JDK 7
あり OK
Linux
Open JDK 7
Windows
Open JDK 14
あり OK
Linux
Open JDK 7
Linux
Open JDK 7
あり OK
Linux
Open JDK 7
Linux
Open JDK 8
あり OK
Linux
Open JDK 7
Linux
Open JDK 14
あり OK
Linux
Open JDK 8
Windows
JRE 6
- 実行不可
Linux
Open JDK 8
Windows
JRE 7
- 実行不可
Linux
Open JDK 8
Windows
JRE 8
あり OK
Linux
Open JDK 8
Windows
Open JDK 7
- 実行不可
Linux
Open JDK 8
Windows
Open JDK 14
あり OK
Linux
Open JDK 8
Linux
Open JDK 7
- 実行不可
Linux
Open JDK 8
Linux
Open JDK 8
あり OK
Linux
Open JDK 8
Linux
Open JDK 14
あり OK
Linux
Open JDK 14
Windows
JRE 6
- 実行不可
Linux
Open JDK 14
Windows
JRE 7
- 実行不可
Linux
Open JDK 14
Windows
JRE 8
- 実行不可
Linux
Open JDK 14
Windows
Open JDK 7
- 実行不可
Linux
Open JDK 14
Windows
Open JDK 14
あり OK
Linux
Open JDK 14
Linux
Open JDK 7
- 実行不可
Linux
Open JDK 14
Linux
Open JDK 8
- 実行不可
Linux
Open JDK 14
Linux
Open JDK 14
あり OK

概ねWindows版と同様の想定通りの結果だったので、macのJavaでも同様になる期待が高い。

圧縮検証プログラムのサンプルコード

急ごしらえのため、雑コード

java
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.IOException;

import java.util.zip.ZipOutputStream;
import java.util.zip.ZipEntry;

public class Main {
    private static void closeQuietly(final Closeable o) {
        try{
            if(o != null) {
                o.close();
            }
        } catch(Exception e){
        }
    }

    public static void main(String[] args) throws IOException {
        System.out.println("hoge");
        System.out.println("java version=" + System.getProperty("java.version"));
        System.out.println("args[0]=" + args[0]);
        System.out.println("args[1]=" + args[1]);
        debugZipArc(args[0], args[1]);
        System.exit(0);
    }

    private static void zipArc(final ZipOutputStream zoStream, final File obj, final String parentDirPath) throws IOException {
        final String currentName =  parentDirPath + obj.getName();
        if(obj.isFile()) {
            FileInputStream fiStream = null;
            try {
                byte buf[] = new byte[4096];
                int len;
                ZipEntry entry = new ZipEntry(currentName);
                fiStream = new FileInputStream(obj);
                zoStream.putNextEntry(entry);
                while((len = fiStream.read(buf)) > 0) {
                    zoStream.write(buf, 0, len);
                }
            } finally {
                closeQuietly(fiStream);
            }
        } else if(obj.isDirectory()) {
            for (File child : obj.listFiles()) {
                zipArc(zoStream, child, currentName + "/");
            }
        }
    }

    private static void debugZipArc(final String inDirPath, final String outFilePath) throws IOException {
        FileOutputStream foStream = null;
        ZipOutputStream zoStream = null;
        try {
            File obj;
            foStream = new FileOutputStream(outFilePath);
            zoStream = new ZipOutputStream(foStream);
            obj = new File(inDirPath);
            zipArc(zoStream, obj, "");
        } finally {
            closeQuietly(zoStream);
            closeQuietly(foStream);
        }
    }
}

補足① JRE6とサロゲート ペア

解凍ツールによっては任意の文字コードでファイル名を展開してくれるものもある。
JRE6ではUTF-8で格納はされている様だけど。👺𩸽 が化けてしまっている。サロゲート ペアを処理する能力は持ち合わせていないのかな、と思われる。
(JavaVMの問題?)
JRE6のZIPの文字化け.png

補足② UNICODE絵文字の表示能力

手元のマシンによっては、UNICODE絵文字が豆腐になるものもあった。同じWindows10、同じ7zipで豆腐になる、ならないがあり、またWinRARでも同様だった。なので、フォントのインストール状況の差異で表示だけの問題かと思われる。
(調査中)
UNICODE絵文字の豆腐.png

補足③ UNICODE対応

それまでシステム文字コードで処理していたのが、国際対応によってUNICODEに置き換わっているものは、ZIPに限らず色々ある。UNICODE ZIPに対応するということは、それらの歩みと同じであり、国際文字対応に於いて非常に意味のある対応である。

※ 日本語文字も国際文字である。

  • 実行ファイル(ネイテイブ) ⇒ Win20000あたりから、内部文字コードがUNICODE (WCHAR)での処理に対応。
  • 実行ファイル(VM) ⇒ Java、.NET CLRはUNICODE (UCS2)で処理。
  • ID3Tag ⇒ 2.3以降でUNICODEに対応。
  • APE Tag ⇒ APEv2でUNICODEに対応。

UNICODEに対応することでシステム文字コードに関わらず、一意の処理で国際文字を扱うことができる。

感想

Javaが割と真っ当にUNICODE ZIPに対応していたのは驚いた。そのため、それなのに未だにUNICODE ZIPが普及出来ていないのはなぜ?と、更に謎が深まった。りあえずJava 7以降であれば標準機能でUNICODE ZIPが使える様なので、マルチ プラットフォームなZIPユーティリティを作るならJavaが結構良さげに感じた。

また、OS側のZIP圧縮機能でUNICODE ZIPに対応しないのもなぜだろう。恐らくmacの方もwinやjavaなどと同様にシステム文字コードで圧縮しただけの、従来の圧縮をしてるだけの様子。しかし、そもそも ZIPファイルはmacのファイル システム向けではない 以上、クロス プラットフォームを無視できないはずなのに、macですらもUNICODE ZIPにしないのがホント謎。

最もmacの場合、ZIPファイルにリソース フォークぶっ込んできている段階で、ルール違反感も否めない。ファイル構成を仕様に盛り込んでる段階で、JARやOffice Open XMLみたいに、表向きだけでもZIPを名乗るの辞めたほうが良いじゃないの?とか思ったりしないでもない。

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?