2009-10-09 9 views
12

Ho a che fare con il codice che esegue varie operazioni di I/O con i file e voglio renderlo in grado di gestire i nomi di file internazionali. Sto lavorando su un Mac con Java 1.5 e se un nome file contiene caratteri Unicode che richiedono surrogati, la JVM non sembra in grado di individuare il file. Ad esempio, il mio file di prova è:Java non può aprire un file con valori Unicode surrogati nel nome file?

"草鷗外.gif" che viene suddiviso in personaggi Java \u8349\uD85B\uDFF6\u9DD7\u5916.gif

Se creo un file da questo nome, non posso aprirlo perché ho un'eccezione FileNotFound. Anche usando questo sulla cartella contenente il file fallirà:

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

La maggior parte del codice che sto effettivamente a che fare con sono di forma:

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

C'è qualche modo per affrontare questo problema, sfuggire ai nomi dei file o aprire file in modo diverso?

+0

Qual è il valore di Charset.defaultCharset() nel proprio ambiente? –

+2

(Sfortunatamente, StackOverflow ha anche un problema con i surrogati e ha rimosso l'ideogramma U + 26FF6 dalla domanda) – bobince

+0

Puoi fornire cosa restituisce System.getProperty ("file.encoding")? Prova a cambiare la tua codifica java -dfile.encoding = ENCODING_GOES_HERE se non funziona o cambia le impostazioni locali del tuo sistema. Se anche questo non funziona, aspetteremo un esperto per risolverlo. – JCasso

risposta

4

Se le impostazioni locali predefinite dell'ambiente non includono quei caratteri, non è possibile aprire il file.

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

Edit: Va bene .. Quello che vi serve è quello di cambiare la lingua del sistema. Qualunque sistema operativo si sta utilizzando.

Edit:

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

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

+0

Non è possibile farlo senza modificare le impostazioni locali del sistema? Il programma che sto costruendo dovrà essere eseguito in qualsiasi locale, e dovrei essere in grado di inserire questi caratteri e gestire questi file anche in un locale americano/inglese. – Bear

+0

Soluzione errata: perché l'applicazione è eseguita su utenti che non sono sul mio computer. E hanno impostazioni locali diverse, e non hanno un vero amministratore per farlo. –

+0

AFAIK non c'è altra soluzione. Questa limitazione viene fornita con Sun/Oracle Java. Puoi provare JFileChooser se la visualizzazione di una finestra di dialogo di salvataggio per gli utenti è OK per te. – JCasso

7

ho il sospetto uno di Java o Mac sta usando CESU-8 al posto di una corretta UTF-8. Java usa "UTF-8 modificato" (che è una leggera variazione di CESU-8) per una varietà di scopi interni, ma non ero consapevole che potesse usarlo come un filesystem/defaultCharset. Sfortunatamente non ho né Mac né Java qui per testare.

"Modificato" è un modo modificato per dire "mal gestito". Invece di emettere un quattro byte sequenza UTF-8 per complementare (non BMP) caratteri come & # x26FF6 ;:

\xF0\xA6\xBF\xB6 

essa stampa una sequenza UTF-8-encoded per ciascuno dei surrogati:

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

Questa non è una sequenza UTF-8 valida, ma molti decodificatori lo consentiranno comunque. Il problema è che se effettui il round-trip su un vero encoder UTF-8 hai una stringa diversa, quella a quattro byte sopra. Prova ad accedere al file con quel nome e boom! fallire.

Quindi, prima facciamo solo controllare come i nomi di file sono in realtà memorizzati sotto il filesystem corrente, utilizzando una piattaforma che utilizza byte per i nomi di file come Python 2.x:

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

Sul mio filesystem (Linux, ext4, UTF -8), il nome del file "草 & # x26FF6; 鷗 外.gif "esce come:

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

che è quello che vuoi. Se questo è ciò che ottieni, probabilmente è Java a sbagliare. Se si ottiene la versione più lunga di sei byte caratteri:

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

è probabilmente OS X facendo è sbagliato ... vuol sempre memorizzano i nomi come questo? (Oppure i file provengono da qualche altra parte in origine?) Che cosa succede se si rinomina il file alla versione 'corretta' ?:

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

Non proprio un bug poiché fa parte delle specifiche (anche se spesso confonde). – finnw

+0

Il risultato dei comandi python era il nome file corretto che hai elencato per primo, quindi è necessario che Java non funzioni correttamente. – Bear

+0

Oh, questo è sfortunato. Anche se hai rilevato la situazione di CESU-8 guasto, non riesco a pensare a un modo per aggirare il problema e ottenere un'interfaccia per i nomi dei file orientata ai byte. :-(Potrebbe essere necessario disabilitare esplicitamente i surrogati fino a quando Sun non lo risolve. – bobince

3

Questo si è rivelato essere un problema con il Mac JVM (testato su 1.5 e 1.6). Non è possibile accedere ai nomi di file contenenti caratteri supplementari/coppie sostitutive con la classe File Java. Ho finito per scrivere una libreria JNI con Carbon chiama per la versione Mac del progetto (ick). Sospetto che la questione del codice CESU-8 sia stata menzionata da bobince, dato che la chiamata JNI per ottenere caratteri UTF-8 ha restituito una stringa CESU-8. Non sembra che tu possa davvero andare in giro.

0

Si tratta di un bug nella vecchia versione di file Java, forse solo su un Mac? Ad ogni modo, la nuova java.nio api funziona molto meglio. Ho diversi file contenenti caratteri unicode e contenuto che non è riuscito a caricare utilizzando java.io.File e le classi correlate. Dopo aver convertito tutto il mio codice per usare java.nio.Path TUTTO ha iniziato a funzionare. E ho sostituito org.apache.commons.io.FileUtils (che ha lo stesso problema) con java.nio.Files ...

... e assicurati di leggere e scrivere il contenuto del file utilizzando un set di caratteri appropriato, ad esempio: Files.readAllLines (myPath, StandardCharsets.UTF_8)