2009-10-09 19 views
12

Estoy tratando con código que hace varias operaciones de IO con archivos, y quiero que sea capaz de manejar nombres de archivos internacionales. Estoy trabajando en una Mac con Java 1.5, y si un nombre de archivo contiene caracteres Unicode que requieren sustitutos, la JVM parece no poder ubicar el archivo. Por ejemplo, mi archivo de prueba es:Java no puede abrir un archivo con valores Unicode subrogantes en el nombre de archivo?

"草鷗外.gif" que consigue roto en los caracteres Java \u8349\uD85B\uDFF6\u9DD7\u5916.gif

Si se crea un archivo de este nombre de archivo, no puedo abrirlo porque me sale una excepción FileNotFound. Incluso el uso de este en la carpeta que contiene el archivo fallará:

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

La mayor parte del código que estoy realmente tratando son de la forma:

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

¿Hay alguna manera de que pueda hacer frente a este problema, ¿escapando de los nombres de archivo o abriendo archivos de manera diferente?

+0

¿Cuál es el valor de Charset.defaultCharset() en su entorno? –

+2

(Desafortunadamente, StackOverflow también tiene un problema con los sustitutos, y ha quitado el ideograma U + 26FF6 de la pregunta) – bobince

+0

¿Puede proporcionar lo que System.getProperty ("file.encoding") devuelve? Intente cambiar su codificación java -dfile.encoding = ENCODING_GOES_HERE si no funciona ni cambia la configuración regional de su sistema. Si esto tampoco funciona o esperamos, esperaremos que un experto lo resuelva. – JCasso

Respuesta

4

Si la configuración regional predeterminada de su entorno no incluye esos caracteres, no puede abrir el archivo.

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

Editar: bien .. Lo que necesita es cambiar la configuración regional del sistema. Cualquiera que sea el sistema operativo que estés usando.

Editar:

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

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

+0

¿No es posible hacerlo sin cambiar la configuración regional del sistema? El programa que estoy creando tendrá que ejecutarse en cualquier configuración regional, y debería poder ingresar estos caracteres y tratar estos archivos incluso en una configuración regional de EE. UU./Inglés. – Bear

+0

Mala solución: porque la aplicación se ejecutó en los usuarios, lo que no está en mi computadora. Y tienen una configuración regional diferente, y no tienen el administrador adecuado para hacer esto. –

+0

AFAIK no hay otra solución. Esta limitación viene con Sun/Oracle Java. Puedes probar JFileChooser si mostrar un cuadro de diálogo para guardar a tus usuarios está bien para ti. – JCasso

7

sospecho una de Java o Mac está utilizando en lugar de CESU-8 adecuada UTF-8. Java usa "UTF-8 modificado" (que es una pequeña variación de CESU-8) para una variedad de propósitos internos, pero no sabía que podría usarlo como un sistema de archivos/defaultCharset. Desafortunadamente no tengo ni Mac ni Java aquí para probar.

"Modificado" es una forma modificada de decir "mal escuchado". En lugar de dar salida a una UTF-8 secuencia de cuatro bytes para suplementaria (no BMP) caracteres como & # x26FF6 ;:

\xF0\xA6\xBF\xB6 

emite una secuencia codificada-UTF-8 para cada uno de los sustitutos:

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

Esta no es una secuencia UTF-8 válida, pero muchos decodificadores lo permitirán de todos modos. El problema es que si hace un viaje de ida y vuelta, a través de un codificador UTF-8 real tiene una cadena diferente, la de cuatro bytes anterior. ¡Intenta acceder al archivo con ese nombre y auge! fallar.

Así que primero vamos a comprobar cómo los nombres de archivo se almacenan realmente en virtud de su sistema de archivos actual, utilizando una plataforma que utiliza bytes para nombres de archivo como Python 2.x:

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

En mi sistema de archivos (Linux, ext4, UTF -8), el nombre del archivo "草 & # x26FF6; 鷗 外.gif "sale como:

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

que es lo que quieres. Si eso es lo que obtienes, es probable que Java lo esté haciendo mal. Si tienes la versión más larga de seis bytes caracteres:

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

es probable que sea OS X haciendo mal ... qué siempre almacenar los nombres de archivo de este tipo? (¿O es que los archivos vienen de otro lugar originalmente?) ¿Qué pasa si cambia el nombre del archivo a la versión 'adecuado' ?:

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

No es realmente un error, ya que es parte de la especificación (incluso si a menudo es confuso). – finnw

+0

El resultado de los comandos de python fue el nombre de archivo correcto que enumeró primero, por lo que debe ser que Java no se juegue bien. – Bear

+0

Oh, eso es desafortunado. Incluso si detectó la situación de CESU-8 defectuosa, no puedo pensar en ninguna forma de evitarlo y obtener una interfaz de nombre de archivo orientada a bytes. :-(Es posible que tenga que rechazar explícitamente los sustitutos hasta el momento en que Sun lo arregle. Qué pobre. – bobince

3

Esto resultó ser un problema con el Mac JVM (probado en 1.5 y 1.6) No se puede acceder a los nombres de archivo que contienen caracteres suplementarios/pares suplentes con la clase Archivo de Java. Terminé escribiendo una biblioteca JNI con llamadas de carbono para la versión de Mac del proyecto (ick). Sospecho que se mencionó el bobince de la edición CESU-8, ya que la llamada JNI para obtener caracteres UTF-8 devolvió una cadena CESU-8. No parece que sea algo que realmente puedas mover.

0

Es un error en la aplicación del archivo java del viejo skool, ¿tal vez solo en un mac? De todos modos, la nueva API java.nio funciona mucho mejor. Tengo varios archivos que contienen caracteres Unicode y contenido que no se pudo cargar utilizando java.io.File y las clases relacionadas. Después de convertir todo mi código para usar java.nio.Path TODO comenzó a funcionar. Y reemplacé org.apache.commons.io.FileUtils (que tiene el mismo problema) con java.nio.Files ...

... y asegúrese de leer y escribir el contenido del archivo usando un juego de caracteres apropiado, por ejemplo: Files.readAllLines (myPath, StandardCharsets.UTF_8)

Cuestiones relacionadas