File.list () récupère incorrectement les noms de fichiers avec des caractères non-ASCII sous Mac OS X lors de l’utilisation de Java 7 à partir d’Oracle

J’ai un problème lors de l’utilisation de File.list () avec des noms de fichier contenant des caractères non-ASCII extraits de manière incorrecte sous Mac OS X lors de l’utilisation de Java 7 à partir d’Oracle.

J’utilise l’exemple suivant:

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

En exécutant cet exemple avec Java 6 d’Apple, tout va bien:

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

En exécutant cet exemple avec Java 7 à partir d’Oracle, le résultat est le suivant:

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

Mais, si je configure l’environnement comme suit (non défini dans les deux cas ci-dessus):

 LANG=en_US.UTF-8 

Le résultat avec Java 7 d’Oracle est le suivant:

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

Mon problème est que je ne veux pas définir la variable d’environnement LANG. Il s’agit d’une application graphique que je souhaite déployer en tant qu’application Mac OS X, et ce, en utilisant le paramètre LSEnvironment.

 LSEnvironment  LANG en_US.UTF-8  

dans Info.plist est sans effet (voir aussi ici )

Que puis-je faire pour récupérer les noms de fichiers correctement dans Java 7 à partir d’Oracle sur Mac OS X sans avoir à définir l’environnement LANG? Sous Windows et Linux, ce problème n’existe pas.

MODIFIER:

Si j’imprime les octets individuels avec:

 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(); 

les résultats corrects sont:

 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 

et les mauvais résultats sont:

 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 

On peut donc voir que Files.list () remplace certains octets avec UTF-8 “EF BF BD” = Unicode U + FFFD = Caractère de remplacement, si LANG n’est pas défini (uniquement Java 7 d’Oracle).

Si tout le rest échoue, créez un wrapper pour la machine virtuelle Java qui définit la variable d’environnement LC_CTYPE, puis lance votre application. OS X ne se soucie pas du programme que le pliste lui demande de faire, le fait? Il est probablement plus simple de créer ce wrapper dans un script shell:

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

Le problème est lié à la manière dont Java – toute version de Java, d’Apple ou d’Oracle – lit les noms des fichiers à partir du système de fichiers. Les noms de fichiers sur le système de fichiers sont essentiellement des données binarys, et ils doivent être décodés pour pouvoir être utilisés en tant que chaîne dans Java. (Vous pouvez en savoir plus sur ce problème dans mon blog.)

La détection de l’encodage varie d’une plate-forme à l’autre et d’une version à l’autre. Apple Java 6 et Oracle Java 7 sont donc différents: Java 6 détecte correctement que le système est défini sur UTF-8, tandis que Java 7 se trompe.

Curieusement, lorsque j’essaie de reproduire le problème avec le programme suivant, je trouve que Java 6 et Java 7 utilisent correctement UTF-8 pour décoder les noms de fichiers (ils sont imprimés correctement sur le terminal). Pour les autres E / S, Java 6u35 utilise MacRoman comme jeu de caractères par défaut, tandis que Java 7u7 utilise UTF-8 (indiqué par la propriété système file.encoding ).

 import java.io.*; public class Test { public static void main(Ssortingng[] 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()); } } } 

Lorsque locale les locale sur OS 10.7, j’obtiens cette sortie. Il semble que sur mon système, Java 6 n’interprète pas correctement la valeur donnée pour LC_CTYPE. Autant que je sache, le système n’a pas de personnalisation et tout est défini en anglais. Il devrait donc s’agir de la configuration par défaut:

 LANG= LC_COLLATE="C" LC_CTYPE="UTF-8" LC_MESSAGES="C" LC_MONETARY="C" LC_NUMERIC="C" LC_TIME="C" LC_ALL= 

Comme exécuter à partir de Java6 donne un résultat correct, est-ce que ceci:

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

résoudre le problème?

Ce constructeur suggéré interprète explicitement la chaîne listOfFiles [i] comme une chaîne codée UTF-8.

MODIFIER:

Comme il ne fonctionne pas, cela signifie que UTF-8 n’est pas le codage par défaut pour os x. Wikipedia dit que Mac OS Roman est, cependant. Je suggère donc d’essayer:

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

mais cela devrait être le même que

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

Donc, si cela ne fonctionne pas aussi, cela conduit à la conclusion que cela pourrait être un bogue, comme Andrew Thomson l’a dit en commentant votre question.

C’est un bogue connu dans OpenJDK. OS X 10.6 et OS X 10.7 renvoient des valeurs différentes pour les parameters régionaux par défaut. Voir le bogue http://java.net/jira/browse/MACOSX_PORT-204 et http://java.net/jira/browse/MACOSX_PORT-165 . Si vous rencontrez ce problème, votez pour le faire réparer.

Rétrograder votre JDK vers le JDK Mac OSX intégré. Si vous le faites, le problème devrait disparaître.

En outre, vous pouvez également définir votre configuration d’exécution dans Eclipse pour qu’elle s’exécute en tant que UTF-8.

C’est un bug dans l’ancien fichier ji api du fichier (peut-être juste sur un mac). Quoi qu’il en soit, tout est corrigé dans le nouveau fichier java.nio.

J’ai plusieurs fichiers contenant des caractères Unicode dans le nom de fichier et le contenu qui n’ont pas pu être chargés avec java.io.File et les classes associées. Après avoir converti tout mon code pour utiliser java.nio.Path, TOUT a commencé à fonctionner. Et j’ai remplacé org.apache.commons.io.FileUtils (qui a le même problème) avec java.nio.Files …

… et assurez-vous de lire et d’écrire le contenu du fichier en utilisant un jeu de caractères approprié, par exemple: Files.readAllLines (myPath, StandardCharsets.UTF_8)