2013-07-04 34 views
5

Metoda getResourceAsStream zwraca wartość null za każdym razem, gdy uruchamia się plik wykonywalny w katalogu, który kończy się wykrzyknikiem.Nie można otworzyć zasobów w katalogach kończących się wykrzyknikiem (!)

Na poniższym przykładzie Mam projektu Eclipse następującą strukturę katalogów:

src\ (Source Folder) 
    main\ (Package) 
     Main.java 
    res\ (Source Folder) 
     images\ 
      Logo.png 

Czytam logo.png następująco:

public static void main(String[] args) throws IOException { 
    try (InputStream is = Main.class.getClassLoader().getResourceAsStream("images/Logo.png")) { 
     Image image = ImageIO.read(is); 
     System.out.println(image); 
    } 
} 

Patrz załącznik 2 do testu przypadki. Po pierwsze, plik wykonywalny jest uruchamiany z katalogu "D: \ test123! @ #" Bez żadnych problemów. Po drugie, plik wykonywalny jest uruchamiany z katalogu "D: \ test123! @ # !!!", z problemami.

Czy katalogi kończące się wykrzyknikiem nie są obsługiwane? Czy kod jest niewłaściwy?

Z góry dziękuję.

Error when running the executable jar in a directory ending with !

+0

Czy istnieje powód, aby tworzyć/używać katalogów o normalnych nazwach? – mtk

+0

Czy jesteś pewien, że umieścisz równe pliki jar w obu katalogach? – Andremoniy

+0

Użytkownicy mogą wykonywać moją aplikację z dowolnego miejsca w systemie plików. Katalogi z wykrzyknikami są obsługiwane przez system Windows. – Velth

Odpowiedz

7

Prawdopodobnie z powodu tego błędu lub którykolwiek z wielu podobnych błędów w bazie danych błędów Java: „/”

http://bugs.sun.com/view_bug.do?bug_id=4523159

Powodem jest to, że w adresie URL słoik jest interpretowany jako separator między nazwą pliku JAR a ścieżką wewnątrz samego JAR. Jeśli nazwa katalogu kończy się na!, Sekwencja znaków "! /" Na końcu katalogu jest niepoprawnie interpretowana. W twoim przypadku, to są rzeczywiście próbuje uzyskać dostęp do zasobu z następującym adresem URL:

jar: file: /// D: /images/Logo.png

/test1231 @ # !!! /test.jar!

Błąd został otwarty przez prawie 12 lat i prawdopodobnie nie zostanie naprawiony. Właściwie to nie wiem, jak można to naprawić bez naruszania innych rzeczy. Problemem jest decyzja o wyborze projektu! jako postać o specjalnym znaczeniu (separatora) na schemacie URL dla plików JAR:

jar:<URL for JAR file>!/<path within the JAR file> 

Ponieważ wykrzyknik jest dozwolone znaków w adresach URL, może to nastąpić zarówno w adresie URL do samego pliku JAR, jak jak również w ścieżce w pliku JAR, uniemożliwiając w niektórych przypadkach znalezienie właściwego separatora "! /".

+0

Pomyślałem, że musiał zrobić coś z Javą i parsować adresy URL przez "! /", Ale po prostu nie mogłem uwierzyć, że to będzie błędem. W każdym razie, czy istnieje możliwość obejścia tego problemu? – Velth

+0

Nie, jak również odnotowano w przypadku błędu, z którym łączyłem, nie ma trywialnego obejścia tego problemu. – jarnbjo

1

Prostym zadaniem dla systemu Windows jest użycie "\" zamiast "/" w ścieżce. Oznaczałoby to, że sekwencja znaków "! /" Znajduje się po pełnej ścieżce. Na przykład:

new URL("jar:file:\\d:\\[email protected]#!!!\\test.jar!/images/Logo.png"); 

mój kod:

File jar = new File(jarPath + "/" + jarName); 
URL url = new URL("jar:" + jar.toURI() + "!" + dataFilePath); 
InputStream stream = null; 
try { 
    stream = url.openStream(); 
} catch (FileNotFoundException e) { 
    // Windows fix 
    URL urlFix = new URL("jar:" + jar.toURI().toString().replace('/', '\\') 
     + "!" + dataFilePath); 
    stream = urlFix.openStream(); 
} 

używam Touri(), ponieważ obsługuje on takie rzeczy jak przestrzenie.

Poprawki:

Rozwiązaniem sama byłaby dla Java, aby sprawdzić, czy plik istnieje i czy nie przejść do następnego separatora (część adresu URL „/”), aż separatory są wyczerpane, a następnie rzucać wyjątek. Tak więc zobaczyłoby to "d: \ test1231 @ # !!" generuje wyjątek java.io.FileNotFoundException, a następnie wypróbował "d: \ test1231 @ # !!! \ test.jar", który istnieje. W ten sposób nie ma znaczenia, czy są "!" w ścieżce pliku lub w plikach jar.

Alternatywnie "! /" Można zmienić na coś innego, co jest nielegalną nazwą pliku lub na coś konkretnego (np. "Jarpath:").

Można również użyć ścieżki pliku słoika, używając innego parametru.

Uwaga:

może być możliwe, aby zastąpić coś zamienić obsługi, lub zmienić kod, aby otworzyć plik pierwszy wtedy zajrzeć do pliku jar później ale nie spojrzał.