2009-10-09 11 views
12

Mam do czynienia z kodem, który wykonuje różne operacje IO z plikami, i chcę, aby był w stanie radzić sobie z międzynarodowymi nazwami plików. Pracuję na komputerze Mac z Javą 1.5, a jeśli nazwa pliku zawiera znaki Unicode, które wymagają surogatów, JVM nie może zlokalizować pliku. Na przykład, mój plik testowy jest:Java nie może otworzyć pliku z surogatycznymi wartościami Unicode w nazwie pliku?

"草鷗外.gif" który zostanie podzielony na znaki Java \u8349\uD85B\uDFF6\u9DD7\u5916.gif

Jeśli utworzyć plik z tego pliku, nie mogę go otworzyć, ponieważ otrzymuję wyjątek FileNotFound. Nawet przy tym na folder zawierający plik zawiedzie:

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

Większość kodu Jestem rzeczywiście do czynienia z są postaci:

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

Czy jest jakiś sposób mogę rozwiązać ten problem, czy inaczej unikniesz nazw plików lub otwierania plików?

+0

Jaka jest wartość zestawu Charset.defaultCharset() w twoim środowisku? –

+2

(Niestety, StackOverflow ma również problem z surogatami i usunęło ideogram U + 26FF6 z pytania) – bobince

+0

Czy możesz podać, co zwraca System.getProperty ("file.encoding")? Spróbuj zmienić kodowanie java-pdfile.encoding = ENCODING_GOES_HERE, jeśli to nie działa, zmień ustawienia regionalne systemu. Jeśli to też nie zadziała, poczekamy, aż ekspert go rozwiąże. – JCasso

Odpowiedz

4

Jeśli domyślne ustawienia regionalne środowiska nie zawierają tych znaków, nie można otworzyć pliku.

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

Edit: porządku .. Co potrzebne jest, aby zmienić ustawienia regionalne systemu. Niezależnie od systemu operacyjnego, z którego korzystasz.

Edit:

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

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

+0

Czy nie można tego zrobić bez zmiany ustawień regionalnych? Program, który buduję, będzie musiał działać w dowolnej lokalizacji, i powinienem móc wprowadzić te znaki i poradzić sobie z tymi plikami nawet w amerykańskim/angielskim języku. – Bear

+0

Złe rozwiązanie - ponieważ aplikacja jest uruchamiana dla użytkowników, którzy nie siedzą na moim komputerze. I mają różne ustawienia narodowe, i nie mają do tego administratora. –

+0

AFAIK nie ma innego rozwiązania. To ograniczenie dotyczy oprogramowania Sun/Oracle Java. Możesz wypróbować JFileChooser, jeśli wyświetlenie okna dialogowego zapisu dla twoich użytkowników jest OK. – JCasso

7

podejrzewam jeden z Java lub Mac używa CESU-8 zamiast prawidłowego UTF-8. Java używa "zmodyfikowanego UTF-8" (co jest niewielką odmianą CESU-8) do różnych celów wewnętrznych, ale nie wiedziałem, że może go użyć jako systemu plików/defaultCharset. Niestety nie mam tutaj ani Maca, ani Javy, aby przetestować.

"Zmodyfikowany" to zmodyfikowany sposób mówienia "źle zainfekowany". Zamiast wyświetlania czterech bajtów UTF-8 sekwencję uzupełniającego (nie-BMP) znaków, jak i # x26FF6 ;:

\xF0\xA6\xBF\xB6 

wyprowadza UTF-8-kodowanej sekwencji dla każdego z zastępcze:

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

To nie jest poprawna sekwencja UTF-8, ale wiele dekoderów i tak to pozwoli. Problem polega na tym, że podczas podróży w obie strony za pomocą prawdziwego kodera UTF-8 masz inny ciąg znaków, czterobajtowy powyżej. Spróbuj uzyskać dostęp do pliku o tej nazwie i bum! zawieść.

Więc najpierw niech po prostu sprawdzić, jak nazwy plików są właściwie przechowywane w bieżącym systemie plików, wykorzystując platformę, która używa bajtów dla nazwach takich jak Python 2.x:

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

Na moim systemie plików (Linux, ext4, UTF -8), nazwa pliku "草 & # x26FF6; 鷗 外.gif "wychodzi jako:

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

czego chcesz. Jeśli tak właśnie jest, prawdopodobnie Java robi to źle. Jeśli masz dłuższą wersję sześć bajtów znaków:

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

to chyba OS X robi to źle ... to zawsze przechowywać nazwy plików w taki sposób? (Czy też pliki skądś indziej oryginalnie?) Co jeśli zmienić nazwę pliku na „właściwej” wersji ?:

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

Naprawdę nie jest to błąd, ponieważ jest częścią specyfikacji (nawet jeśli często jest mylące). – finnw

+0

Wynik poleceń Pythona był prawidłową nazwą pliku, którą wymieniłeś jako pierwszą, więc musi to być niezła gra Java. – Bear

+0

To niefortunne. Nawet jeśli wykryjesz zepsutą sytuację CESU-8, nie mogę wymyślić żadnego sposobu obejścia tego problemu i uzyskania interfejsu nazw bajtów. :-(Być może będziesz musiał jawnie zabronić zastępstwom aż do czasu, w którym Sun to naprawi. – bobince

3

okazało się to być problem z Mac JVM (testowane na 1.5 i 1.6). Do plików o dodatkowych znakach/parach zastępczych nie można uzyskać dostępu za pomocą klasy Java File. Skończyłem na pisaniu biblioteki JNI z wywołaniami Carbon dla wersji Mac projektu (ick). Podejrzewam, że wspomniano o problemie CESU-8, ponieważ wywołanie JNI, aby uzyskać znaki UTF-8, zwróciło ciąg CESU-8. Nie wygląda na to, że naprawdę można się obejść.

0

To błąd w starej apce pliku Java java, może tylko na macu? W każdym razie nowy aplet java.nio działa znacznie lepiej. Mam kilka plików zawierających znaki Unicode i treści, których nie udało się wczytać przy użyciu pliku java.io.File i powiązanych klas. Po konwersji całego mojego kodu na użytek java.nio.Path WSZYSTKO zaczęło działać. I zamieniłem org.apache.commons.io.FileUtils (z tym samym problemem) z java.nio.Files ...

... i pamiętaj, aby odczytywać i zapisywać zawartość pliku przy użyciu odpowiedniego zestawu znaków, na przykład: Files.readAllLines (myPath, StandardCharsets.UTF_8)

Powiązane problemy