Mam ten kod, który czyta wszystkie pliki z katalogu.
File textFolder = new File("text_directory");
File [] texFiles = textFolder.listFiles( new FileFilter() {
public boolean accept( File file ) {
return file.getName().endsWith(".txt");
}
});
Działa świetnie. Wypełnia tablicę wszystkimi plikami kończącymi się na „.txt” z katalogu „text_directory”.
Jak można odczytać zawartość katalogu, w podobny sposób w pliku JAR?
To, co naprawdę chcę zrobić, to wymienić wszystkie obrazy w moim pliku JAR, aby móc je załadować za pomocą:
ImageIO.read(this.getClass().getResource("CompanyLogo.png"));
(To działa, ponieważ „CompanyLogo” jest „zakodowane na stałe”, ale liczba obrazów w pliku JAR może wynosić od 10 do 200 zmiennej długości).
EDYTOWAĆ
Więc myślę, że moim głównym problemem byłoby: Jak poznać nazwę pliku JAR, w którym mieszka moja główna klasa?
Przyznane, że mogłem to przeczytać za pomocą java.util.Zip
.
Moja struktura wygląda tak:
Oni są jak:
my.jar!/Main.class
my.jar!/Aux.class
my.jar!/Other.class
my.jar!/images/image01.png
my.jar!/images/image02a.png
my.jar!/images/imwge034.png
my.jar!/images/imagAe01q.png
my.jar!/META-INF/manifest
W tej chwili mogę załadować na przykład plik „images / image01.png” za pomocą:
ImageIO.read(this.getClass().getResource("images/image01.png));
Ale tylko dlatego, że znam nazwy plików, do reszty muszę je ładować dynamicznie.
Odpowiedzi:
Zwróć uwagę, że w Javie 7 możesz utworzyć plik
FileSystem
JAR (zip), a następnie przeszukać go za pomocą mechanizmów przechodzenia po katalogach i filtrowania NIO. Ułatwiłoby to pisanie kodu obsługującego pliki JAR i „eksplodowane” katalogi.źródło
Kod, który działa zarówno dla plików IDE, jak i .jar:
źródło
FileSystems.newFileSystem()
zajmuje aMap<String, ?>
, więc musisz określićCollections.emptyMap()
, że ma zwrócić odpowiednio wpisany. Działa to:Collections.<String, Object>emptyMap()
.fileSystem
!walk
metoda wFiles
jest dostępna tylko w 1.8). Jedynym problemem jest to, że katalog zasobów pojawia się wFiles.walk(myPath, 1)
pliku, a nie tylko w plikach. Myślę, że pierwszy element można po prostu zignorowaćmyPath = fileSystem.getPath("/resources");
nie działa dla mnie; nic nie znajduje. W moim przypadku powinno to być "obrazy", a katalog "obrazy" jest zdecydowanie zawarty w moim słoiku!odpowiedź Ericksona zadziałała idealnie:
Oto działający kod.
I właśnie zmodyfikowałem moją metodę ładowania z tego:
Do tego:
źródło
Chciałbym rozwinąć odpowiedź acheron55 , ponieważ jest to bardzo niebezpieczne rozwiązanie z kilku powodów:
FileSystem
obiektu.FileSystem
obiekt już istnieje.To jest nieco bezpieczniejsze rozwiązanie:
Nie ma rzeczywistej potrzeby synchronizacji nazwy pliku; można po prostu zsynchronizować ten sam obiekt za każdym razem (lub stworzyć metodę
synchronized
), to czysta optymalizacja.Powiedziałbym, że jest to nadal problematyczne rozwiązanie, ponieważ w kodzie mogą znajdować się inne części, które używają
FileSystem
interfejsu na tych samych plikach, co może kolidować z nimi (nawet w aplikacji jednowątkowej).Nie sprawdza też
null
s (na przykład ongetClass().getResource()
.Ten konkretny interfejs Java NIO jest trochę okropny, ponieważ wprowadza globalny / pojedynczy zasób, który nie jest bezpieczny dla wątków, a jego dokumentacja jest bardzo niejasna (wiele niewiadomych ze względu na implementacje specyficzne dla dostawcy). Wyniki mogą się różnić w przypadku innych
FileSystem
dostawców (nie JAR). Może jest dobry powód, dla którego tak jest; Nie wiem, nie badałem wdrożeń.źródło
Zakładając, że Twój projekt jest zapakowany w Jar (niekoniecznie prawda!), Możesz użyć ClassLoader.getResource () lub findResource () z nazwą klasy (po której następuje .class), aby uzyskać jar zawierający daną klasę. Będziesz musiał przeanalizować nazwę słoika z adresu URL, który zostanie zwrócony (nie taki trudny), co zostawię jako ćwiczenie dla czytelnika :-)
Pamiętaj, aby przetestować przypadek, w którym klasa nie jest częścią słoika.
źródło
CodeSource
.Mam przeniesiony odpowiedź acheron55 w Java 7 i zamknął
FileSystem
obiekt. Ten kod działa w IDE, w plikach jar i w jar w trakcie wojny z Tomcat 7; ale zwróć uwagę, że nie działa w słoiku wewnątrz wojny na JBoss 7 (dajeFileSystemNotFoundException: Provider "vfs" not installed
, zobacz także ten post ). Ponadto, podobnie jak oryginalny kod, nie jest bezpieczny dla wątków, jak sugeruje errr . Z tych powodów porzuciłem to rozwiązanie; jeśli jednak możesz zaakceptować te kwestie, oto mój gotowy kod:źródło
Oto metoda, którą napisałem dla „uruchomienia wszystkich JUnits w pakiecie”. Powinieneś być w stanie dostosować go do swoich potrzeb.
Edycja: Ach, w takim przypadku możesz również chcieć tego fragmentu (ten sam przypadek użycia :))
źródło
Oto przykład użycia biblioteki Reflections do rekurencyjnego skanowania ścieżki klas według wzorca nazwy wyrażenia regularnego, wzbogaconego o kilka profitów Guava, aby pobrać zawartość zasobów:
Działa to zarówno w przypadku słoików, jak i klas eksplodowanych.
źródło
Plik jar to po prostu plik ZIP z manifestem strukturalnym. Możesz otworzyć plik jar za pomocą zwykłych narzędzi zip Java i przeskanować w ten sposób zawartość pliku, nadmuchać strumienie itp. Następnie użyj tego w wywołaniu getResourceAsStream, a wszystko powinno być hunky dory.
EDYCJA / po wyjaśnieniu
Zapamiętanie wszystkich drobiazgów zajęło mi minutę i jestem pewien, że można to zrobić czystszym sposobem, ale chciałem zobaczyć, że nie jestem szalony. W moim projekcie image.jpg to plik w jakiejś części głównego pliku jar. Otrzymuję program ładujący klasy głównej (punktem wejścia jest SomeClass) i używam go do odkrywania zasobu image.jpg. Następnie trochę magii strumienia, aby przenieść to do tego elementu ImageInputStream i wszystko jest w porządku.
źródło
new File("blah.JAR")
do utworzenia obiektu File, który reprezentuje plik JAR. Po prostu zastąp „blah.JAR” nazwą swojego pliku JAR.Biorąc pod uwagę rzeczywisty plik JAR, możesz wyświetlić zawartość za pomocą
JarFile.entries()
. Musisz jednak znać lokalizację pliku JAR - nie możesz po prostu poprosić modułu ładującego klasy o listę wszystkiego, do czego może się dostać.Powinno być możliwe ustalenie lokalizacji pliku JAR na podstawie adresu URL zwróconego z
ThisClassName.class.getResource("ThisClassName.class")
, ale może to być trochę kłopotliwe.źródło
new File("baz.jar)
, obiekt File reprezentowałby twój plik JAR.Jakiś czas temu stworzyłem funkcję, która pobiera klasy z wnętrza JARa:
źródło
źródło
Istnieją dwa bardzo przydatne narzędzia, oba o nazwie JarScan:
www.inetfeedback.com/jarscan
jarscan.dev.java.net
Zobacz także to pytanie: JarScan, przeskanuj wszystkie pliki JAR we wszystkich podfolderach pod kątem określonej klasy
źródło
Najbardziej niezawodnym mechanizmem wyświetlania wszystkich zasobów w ścieżce klas jest obecnie używanie tego wzorca z ClassGraph , ponieważ obsługuje on najszerszy możliwy zestaw mechanizmów specyfikacji ścieżki klas , w tym nowy system modułów JPMS. (Jestem autorem ClassGraph.)
Istnieje wiele innych sposobów radzenia sobie z zasobami .
źródło
Po prostu inny sposób wyświetlania / odczytywania plików z adresu URL jar i robi to rekurencyjnie dla zagnieżdżonych plików jar
https://gist.github.com/trung/2cd90faab7f75b3bcbaa
źródło
Jeszcze jeden na drogę:
Jest to nieco bardziej elastyczne w dopasowywaniu określonych nazw plików, ponieważ wykorzystuje globbing z użyciem symboli wieloznacznych.
Bardziej funkcjonalny styl:
źródło