18

Oracle から Java 7 を使用している場合、Mac OS X で非 ASCII 文字を含むファイル名で File.list() を使用すると、正しく取得されないという問題があります。

次の例を使用しています。

import java.io.*;
import java.util.*;

public class ListFiles {

  public static void main(String[] args) 
  {
    try { 
      File folder = new File(".");
      String[] listOfFiles = folder.list(); 
      for (int i = 0; i < listOfFiles.length; i++) 
      {
        System.out.println(listOfFiles[i]);
      }
      Map<String, String> env = System.getenv();
      for (String envName : env.keySet()) {
        System.out.format("%s=%s%n",
            envName,
            env.get(envName));
      }
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
  }

}

この例を Apple の Java 6 で実行すると、すべて問題ありません。

....
Folder-ÄÖÜäöüß
吃饭.txt
....

この例を Oracle の Java 7 で実行すると、結果は次のようになります。

....
Folder-A��O��U��a��o��u����
������.txt
....

ただし、環境を次のように設定すると (上記の 2 つのケースでは設定されません):

LANG=en_US.UTF-8

Oracle の Java 7 での結果は期待どおりです。

....
Folder-ÄÖÜäöüß
吃饭.txt
....

私の問題は、LANG 環境変数を設定したくないということです。これは、Mac OS X アプリケーションとしてデプロイしたい GUI アプリケーションであり、そうすることで、LSEnvironment 設定

<key>LSEnvironment</key>
<dict>
  <key>LANG</key>
  <string>en_US.UTF-8</string>
</dict>

Info.plist では効果がありません (こちらも参照)

LANG 環境を設定せずに Mac OS X 上の Oracle から Java 7 でファイル名を正しく取得するにはどうすればよいですか? Windows および Linux では、この問題は存在しません。

編集:

個々のバイトを次のように印刷すると:

byte[] x = listOfFiles[i].getBytes();
for (int j = 0; j < x.length; j++) 
{
    System.out.format("%02X",x[j]);
    System.out.print(" ");
}
System.out.println();

正しい結果は次のとおりです。

Folder-ÄÖÜäöüß
46 6F 6C 64 65 72 2D 41 CC 88 4F CC 88 55 CC 88 61 CC 88 6F CC 
88 75 CC 88 C3 9F 
吃饭.txt
E5 90 83 E9 A5 AD 2E 74 78 74 

間違った結果は次のとおりです。

Folder-A��O��U��a��o��u����
46 6F 6C 64 65 72 2D 41 EF BF BD EF BF BD 4F EF BF BD EF BF BD 
55 EF BF BD EF BF BD 61 EF BF BD EF BF BD 6F EF BF BD EF BF BD 
75 EF BF BD EF BF BD EF BF BD EF BF BD  
������.txt
EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD EF BF BD 2E 74 78 74 

そのため、LANG が設定されていない場合 (Oracle の Java 7 のみ)、Files.list() が一部のバイトを UTF-8 "EF BF BD" = Unicode U+FFFD = 置換文字に置き換えることがわかります。

4

5 に答える 5

4

他のすべてが失敗した場合は、LC_CTYPE 環境変数を設定してアプリケーションを起動する JVM のラッパーを作成します。OS X は、plist が実行するように指示するプログラムを気にしませんか? このラッパーをシェル スクリプトで作成するのがおそらく最も簡単です。

#!/bin/bash
export LC_CTYPE="UTF-8" # Try other options if this doesn't work
exec java your.program.Here

問題は、Java (Apple または Oracle の Java の任意のバージョン) がファイル システムからファイルの名前を読み取る方法にあります。ファイル システム上のファイルの名前は基本的にバイナリ データであり、Java で文字列として使用するにはデコードする必要があります。(この問題の詳細については、私のブログをご覧ください。)

エンコーディングの検出はプラットフォームごと、バージョンごとに異なるため、Apple Java 6 と Oracle Java 7 の違いはここにあります。Java 6 はシステムが UTF-8 に設定されていることを正しく検出しますが、Java 7 は間違っています。

奇妙なことに、次のプログラムで問題を再現しようとすると、Java 6 と Java 7 の両方が UTF-8 を正しく使用してファイル名をデコードすることがわかりました (それらは端末に正しく出力されます)。その他の I/O については、Java 6u35 はデフォルトの文字セットとして MacRoman を使用していますが、Java 7u7 は UTF-8 を使用しています (file.encodingシステム プロパティによって示されます)。

import java.io.*;

public class Test {
  public static void main(String[] args) {
    System.setOut(new PrintStream(System.out, true, "UTF-8"));
    System.out.println(System.getProperty("file.encoding"));
    for (File f: new File(".").listFiles) {
      System.out.println(g.getName());
    }
  }
}

localeOS 10.7 で実行すると、この出力が得られます。私のシステムでは、Java 6 が LC_CTYPE に指定された値を正しく解釈していないようです。私の知る限り、システムにはカスタマイズがなく、すべてが英語に設定されているため、これがデフォルトの構成になるはずです。

LANG=
LC_COLLATE="C"
LC_CTYPE="UTF-8"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=
于 2012-10-20T11:46:20.123 に答える
2

Java6 から実行すると正しい結果が得られるため、次のようになります。

System.out.println(new String(listOfFiles[i].getBytes(),"UTF-8"));

問題を解く?

この推奨されるコンストラクターは、listOfFiles[i] 文字列を UTF-8 でエンコードされた文字列として明示的に解釈します。

編集:

動作していないため、UTF-8 が OS X のデフォルトのエンコーディングではないことを意味します。ただし、ウィキペディアによると、Mac OS Romanはそうです。だから私は試してみることをお勧めします:

System.out.println(new String(listOfFiles[i].getBytes(),"MacRoman"));

しかし、それ

System.out.println(new String(listOfFiles[i].getBytes()));

したがって、それも機能しない場合は、Andrew Thomson が質問へのコメントで述べたように、バグである可能性があるという結論に至ります。

于 2012-10-20T09:59:53.487 に答える
0

これは、OpenJDK の既知のバグです。OS X 10.6 と OS X 10.7 は、既定のロケールに対して異なる値を返します。バグhttp://java.net/jira/browse/MACOSX_PORT-204およびhttp://java.net/jira/browse/MACOSX_PORT-165を参照してください。この問題が発生している場合は、修正するために投票してください。

于 2012-12-27T14:04:10.440 に答える
0

これは、古い Java File API のバグです (Mac だけかもしれません)。とにかく、それはすべて新しい java.nio で修正されています。

ファイル名に Unicode 文字を含むファイルと、java.io.File および関連クラスを使用してロードできなかったコンテンツがいくつかあります。java.nio.Pathを使用するようにすべてのコードを変換した後、すべてが機能し始めました。そして、org.apache.commons.io.FileUtils(同じ問題があります)をjava.nio.Filesに置き換えました...

...そして、適切な文字セットを使用してファイルの内容を読み書きしてください。たとえば、 Files.readAllLines(myPath, StandardCharsets.UTF_8)

于 2014-02-24T13:58:03.500 に答える