2009-10-09 6 views
12

Je fais affaire avec du code qui effectue diverses opérations d'E/S avec des fichiers, et je veux le rendre capable de traiter des noms de fichiers internationaux. Je travaille sur un Mac avec Java 1.5, et si un nom de fichier contient des caractères Unicode qui nécessitent des substituts, la JVM n'arrive pas à localiser le fichier. Par exemple, mon fichier de test est:Java ne peut pas ouvrir un fichier avec des valeurs Unicode de substitution dans le nom de fichier?

"草鷗外.gif" qui se casse dans les caractères Java \u8349\uD85B\uDFF6\u9DD7\u5916.gif

Si je crée un fichier de ce nom, je ne peux pas l'ouvrir parce que je reçois une exception FileNotFound. Même en utilisant ce sur le dossier contenant le fichier échouera:

File[] files = folder.listFiles(); 
for (File file : files) { 
    if (!file.exists()) { 
     System.out.println("Failed to find File"); //Fails on the surrogate filename 
    } 
} 

La plupart du code que je suis en fait affaire sont de la forme:

FileInputStream instream = new FileInputStream(new File("草鷗外.gif")); 
// operations follow 

Est-il possible que je peux résoudre ce problème, soit échapper les noms de fichiers ou ouvrir des fichiers différemment?

+0

Quelle est la valeur de Charset.defaultCharset() dans votre environnement? –

+2

(Malheureusement, StackOverflow a aussi un problème avec les substituts, et a supprimé l'idéogramme U + 26FF6 de la question) – bobince

+0

Pouvez-vous fournir ce que System.getProperty ("file.encoding") renvoie? Essayez de changer votre encodage java -dfile.encoding = ENCODING_GOES_HERE si cela ne change pas les paramètres régionaux de votre système. Si cela ne fonctionne pas, nous attendrons qu'un expert le résolve. – JCasso

Répondre

4

Si les paramètres régionaux par défaut de votre environnement n'incluent pas ces caractères, vous ne pouvez pas ouvrir le fichier.

Voir: File.exists() fails with unicode characters in name

Edit: D'accord .. Qu'est-ce que vous avez besoin est de modifier les paramètres régionaux du système. Quel que soit l'OS que vous utilisez.

Modifier:

Voir: How can I open files containing accents in Java?

Voir: JFileChooser on Mac cannot see files named by Chinese chars?

+0

Est-ce impossible de le faire sans modifier les paramètres régionaux du système? Le programme que je construis devra fonctionner sur n'importe quel environnement local, et je devrais être capable de saisir ces caractères et de traiter ces fichiers même dans un environnement local US/anglais. – Bear

+0

Mauvaise solution - parce que l'application a fonctionné sur les utilisateurs, qui ne sont pas assis sur mon ordinateur. Et ont des paramètres régionaux différents, et ils n'ont pas d'administrateur rigth pour le faire. –

+0

AFAIK il n'y a pas d'autre solution. Cette limitation vient avec Sun/Oracle Java. Vous pouvez essayer JFileChooser si l'affichage d'une boîte de dialogue de sauvegarde pour vos utilisateurs est OK pour vous. – JCasso

7

je soupçonne que l'un de Java ou Mac utilise CESU-8 au lieu de UTF-8 approprié. Java utilise "UTF-8 modifié" (qui est une légère variation de CESU-8) pour une variété de fins internes, mais je ne savais pas qu'il pourrait l'utiliser comme un système de fichiers/defaultCharset. Malheureusement, je n'ai ni Mac ni Java ici pour tester.

"Modifié" est une façon modifiée de dire "mal encombré". Au lieu de délivrer en sortie un caractère comme & # x26FF6 ;:

\xF0\xA6\xBF\xB6 

séquence UTF-8 pour quatre octets supplémentaires (non-BMP), il émet une séquence codée UTF-8 pour chacun des substituts:

\xED\xA1\x9B\xED\xBF\xB6 

Ce n'est pas une séquence UTF-8 valide, mais beaucoup de décodeurs le permettent de toute façon. Le problème est que si vous faites un aller-retour à travers un vrai codeur UTF-8, vous avez une chaîne différente, celle de quatre octets ci-dessus. Essayez d'accéder au fichier avec ce nom et boom! échouer.

Alors d'abord, nous allons vérifier à quel point les noms de fichiers sont stockés dans votre système de fichiers en cours, en utilisant une plate-forme qui utilise octets pour les noms de fichiers tels que Python 2.x:

$ python 
Python 2.x.something (blah blah) 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import os 
>>> os.listdir('.') 

Sur mon système de fichiers (Linux, ext4, UTF -8), le nom de fichier "草 & # x26FF6; 鷗 外.gif » apparaît comme:

['\xe8\x8d\x89\xf0\xa6\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif'] 

qui est ce que vous voulez. Si c'est ce que vous obtenez, c'est probablement Java qui le fait mal. Si vous obtenez la version plus longue de six caractères octets:

['\xe8\x8d\x89\xed\xa1\x9b\xed\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif'] 

il est probablement OS X faire mal ... il ne stocke toujours les noms de fichiers comme celui-ci? (Ou les fichiers viennent d'ailleurs à l'origine?) Que faire si vous renommez le fichier à la version « correcte » ?:

os.rename('\xe8\x8d\x89\xed\xa1\x9b\xed\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif', '\xe8\x8d\x89\xf0\xa6\xbf\xb6\xe9\xb7\x97\xe5\xa4\x96.gif') 
+2

Pas vraiment un bug car il fait partie de la spécification (même si c'est souvent déroutant.) – finnw

+0

Le résultat des commandes python était le nom de fichier correct que vous avez listé en premier, donc ça doit être Java qui ne joue pas bien. – Bear

+0

Oh, c'est malheureux. Même si vous avez détecté la situation cassée-CESU-8, je ne peux pas penser à un moyen de contourner cela et obtenir une interface de nom de fichier orientée octet. :-(Vous devrez peut-être explicitement interdire les substituts jusqu'au moment où Sun le réparera. – bobince

3

Ce avéré être un problème avec la machine virtuelle Java Mac (testé sur 1,5 et 1,6). Les noms de fichiers contenant des caractères supplémentaires/des paires de substitution ne sont pas accessibles avec la classe Java File. J'ai fini par écrire une bibliothèque JNI avec des appels Carbon pour la version Mac du projet (ick). Je pense que le numéro CESU-8 a été mentionné par Bobince, car l'appel JNI pour obtenir des caractères UTF-8 a renvoyé une chaîne CESU-8. Ne semble pas que c'est quelque chose que vous pouvez vraiment contourner.

0

C'est un bogue dans le fichier api old-skool java, peut-être juste sur un mac? Quoi qu'il en soit, la nouvelle API java.nio fonctionne beaucoup mieux. J'ai plusieurs fichiers contenant des caractères Unicode et le contenu qui a échoué à charger en utilisant java.io.File et les classes connexes. Après avoir converti tout mon code pour utiliser java.nio.Path tout a commencé à travailler. 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 écrire le contenu du fichier en utilisant un jeu de caractères approprié, par exemple: Files.readAllLines (myPath, StandardCharsets.UTF_8)

Questions connexes