Umożliwia odczytywanie pliku tekstowego zasobu do String (Java) [zamknięty]
215
Czy jest jakieś narzędzie, które pomaga odczytać plik tekstowy z zasobu w łańcuch. Przypuszczam, że jest to popularne wymaganie, ale po Googlingu nie mogłem znaleźć żadnego narzędzia.
@JonSkeet Jest to świetne, jednak w przypadku aplikacji internetowych może nie być najlepszym rozwiązaniem, implementacja getResourceużywa, Resource.class.getClassLoaderale w aplikacjach internetowych może to nie być „twój” moduł ładujący, więc zaleca się (np. W [1]) użycie Thread.currentThread().getContextClassLoader().getResourceAsStreamzamiast tego (odniesienie [1]: stackoverflow.com/questions/676250/… )
Eran Medan
2
@EranMedan: Tak, jeśli chcesz kontekstowego modułu ładującego, którego chcesz użyć jawnie.
Jon Skeet
6
W szczególnym przypadku, gdy zasób znajduje się obok twojej klasy, możesz zrobić, Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)co gwarantuje użycie poprawnego modułu ładującego klasy.
Bogdan Calmac
2
com.google.common.io.Resourcesjest oznaczony jako niestabilny zgodnie z SonarQube
Ghilteras,
1
guavazmienił wdrożenie. W przypadku guava 23 wdrożenie lubi podążać. ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
XXY
171
Możesz użyć starej sztuczki Stupid Scanner oneliner, aby to zrobić bez dodatkowej zależności, takiej jak guava:
String text =newScanner(AppropriateClass.class.getResourceAsStream("foo.txt"),"UTF-8").useDelimiter("\\A").next();
Chłopaki, nie używajcie rzeczy innych firm, chyba że naprawdę tego potrzebujecie. JDK ma już wiele funkcji.
Unikanie stron trzecich jest rozsądną zasadą. Niestety, podstawowa biblioteka wydaje się być uczulona na modelowanie rzeczywistych przypadków użycia. Spójrz na pliki Java 7 i powiedz mi, dlaczego nie zawarto tam czytania wszystkiego z zasobu ścieżki klas? Lub przynajmniej używając standardowego „systemu plików”.
Dilum Ranatunga
3
Czy to jest - czy też nie - konieczne jest również zamknięcie strumienia? Guawa wewnętrznie zamyka strumień.
virgo47,
Dla mnie też działało pięknie! Zgadzam się również w kwestii stron trzecich: w przypadku wielu odpowiedzi domyślną odpowiedzią jest zawsze użycie biblioteki innej firmy - czy to od Apache, czy od kogoś innego.
Terje Dahl,
1
zmień, CartApplication.class.getResourceAsStreamaby CartApplication.class.getClassLoader().getResourceAsStreamładować zasoby w bieżącym słoju .. jak srm / test / resources
Chris DaMour
5
Chociaż korzystałem z tego, całkowicie nie zgadzam się na unikanie pakietów innych firm. Fakt, że w Javie jedynym sposobem łatwego odczytu pliku do łańcucha jest sztuczka skanera, jest bardzo smutna. Alternatywą dla korzystania z biblioteki innej firmy jest to, że każdy po prostu utworzy własne opakowanie. Guava dla IO wygrywa, jeśli masz wiele potrzeb dla tego rodzaju operacji. Zgadzam się, że nie powinieneś importować pakietu innej firmy, jeśli masz tylko jedno miejsce w kodzie, w którym chcesz to zrobić. To byłoby przesadne imo.
Wyjaśnij, dlaczego to działa, dlaczego jest lepsze niż inne alternatywy, oraz wszelkie niezbędne rozważania dotyczące wydajności / kodowania.
nanofarad
5
To jest nio 2 w java 1.7. To rodzima faza javy. Do kodowania użyj nowego ciągu (bajty, StandardCharsets.UTF_8)
Kovalsky Dmitryi
5
w moim przypadku potrzebowałem, getClass().getClassLoader()ale poza tym świetnego rozwiązania!
Emmanuel Touzery,
3
To nie zadziała, gdy aplikacja zostanie spakowana do słoika.
Daniel Bo
65
Czyste i proste, przyjazne dla słoików rozwiązanie Java 8+
Ta prosta metoda poniżej będzie dobrze, jeśli używasz Java 8 lub nowszej:
/**
* Reads given resource file as a string.
*
* @param fileName path to the resource file
* @return the file's contents
* @throws IOException if read fails for any reason
*/staticString getResourceFileAsString(String fileName)throwsIOException{ClassLoader classLoader =ClassLoader.getSystemClassLoader();try(InputStream is = classLoader.getResourceAsStream(fileName)){if(is ==null)returnnull;try(InputStreamReader isr =newInputStreamReader(is);BufferedReader reader =newBufferedReader(isr)){return reader.lines().collect(Collectors.joining(System.lineSeparator()));}}}
Działa również z zasobami w plikach jar .
Informacje o kodowaniu tekstu: InputStreamReaderużyje domyślnego zestawu znaków systemowych, jeśli go nie określisz. Możesz to określić samodzielnie, aby uniknąć problemów z dekodowaniem, takich jak:
newInputStreamReader(isr,StandardCharsets.UTF_8);
Unikaj niepotrzebnych zależności
Zawsze wolę nie polegać na dużych, grubych bibliotekach. O ile nie używasz już Guava lub Apache Commons IO do innych zadań, dodanie tych bibliotek do projektu, aby móc czytać z pliku, wydaje się trochę za dużo.
Metoda „prosta”? Chyba żartujesz
Rozumiem, że czysta Java nie wykonuje dobrej roboty, jeśli chodzi o wykonywanie prostych zadań takich jak ten. Na przykład tak czytamy z pliku w Node.js:
Prosty i łatwy do odczytania (chociaż ludzie nadal lubią polegać na wielu zależnościach, głównie z powodu niewiedzy). Lub w Pythonie:
with open('some-file.txt','r')as f:
content = f.read()
To smutne, ale nadal jest proste w stosunku do standardów Java i wystarczy, że skopiujesz powyższą metodę do swojego projektu i użyjesz jej. Nawet nie proszę o zrozumienie, co się tam dzieje, ponieważ to naprawdę nie ma znaczenia dla nikogo. To po prostu działa, kropka :-)
@zakmck staraj się zachować konstruktywność swoich komentarzy. Gdy dorastasz jako dojrzały programista, dowiadujesz się, że czasami chcesz „odkryć koło”. Na przykład może być konieczne utrzymanie pliku binarnego poniżej pewnego progu. Biblioteki często zwiększają rozmiar aplikacji o rząd wielkości. Można argumentować wręcz przeciwnie do tego, co powiedziałeś: „Nie trzeba pisać kodu. Tak, za każdym razem importujmy biblioteki”. Czy naprawdę wolisz importować bibliotekę, aby zaoszczędzić Ci 3 wiersze kodu? Założę się, że dodanie biblioteki zwiększy Twój LOC o więcej. Kluczem jest równowaga.
Lucio Paiva,
3
Cóż, nie każdy działa w chmurze. Na przykład wszędzie są systemy osadzone z uruchomioną Javą. Po prostu nie widzę twojego sensu w krytykowaniu odpowiedzi, które zapewniają całkowicie poprawne podejście, biorąc pod uwagę, że wspomniałeś o sobie, że przyjmiesz sugestię użycia JDK bezpośrednio we własnym kodzie. W każdym razie, starajmy się zachować komentarze wyłącznie w celu poprawy odpowiedzi, a nie dyskusji na temat opinii.
Lucio Paiva,
1
Dobre rozwiązanie tylko dla JDK. Dodałbym tylko sprawdzenie, czy InputStreamzmienna isjest, nullczy nie.
scrutari
2
Miły. Użyłem tego. Możesz również rozważyć zamknięcie strumieni / czytników.
dimplex
1
@RobertBain Zredagowałem odpowiedź, aby dodać informacje o ostrzeżeniu o zestawie znaków. Daj mi znać, jeśli dowiesz się, co poszło nie tak z modułem ładującym w AWS, abym mógł dodać to również do odpowiedzi. Dzięki!
Lucio Paiva,
57
Guava ma metodę „toString” do odczytu pliku do ciągu:
Lub jeśli jest to strumień wejściowy, guawa również ma dobry sposób na toString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Podobnie jak kompaktu, ale z właściwego zamykania strumienia wejściowego: IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8").
Bogdan Calmac
1
Jeśli to rozwiązanie nie działa, spróbuj dodać getClassLoader()do łańcucha metod: String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
URL url =Resources.getResource("myFile.txt");File myFile =newFile(url.toURI());String content =FileUtils.readFileToString(myFile,"UTF-8");// or any other encoding
Dlaczego trzeba określić kodowanie, nie rozumiem tego. Jeśli czytam plik, chcę tylko, co jest w nim, powinien dowiedzieć się, jakie to kodowanie, tak jak robi to mój edytor. Kiedy otwieram w Notatniku lub ++, nie mówię, jakiego kodowania powinien użyć. Korzystam z tej metody, a następnie writeStringToFile ... ale zawartość jest inna. W sklonowanym pliku pojawiają się dziwne tokeny. Nie rozumiem, dlaczego powinienem określić kodowanie.
mmm,
11
@Hamidan, wybór odpowiedniego kodowania jest bardzo złożonym algorytmem. Często jest zaimplementowany w edytorze tekstu, ale czasami nie wykrywa poprawnego kodowania. Nie spodziewałbym się, że interfejs API do odczytu plików osadzi tak złożony algorytm do odczytu mojego pliku.
Vincent Robert
1
@SecretService Ponadto te algorytmy wykorzystują informacje, takie jak język systemu operacyjnego, ustawienia regionalne i inne ustawienia regionalne, co oznacza, że odczyt pliku bez określenia kodowania może działać w konfiguracji, ale nie w cudzym.
Nie sądzę, że to zadziała, jeśli zasób zostanie znaleziony w słoiku. To nie będzie plik.
Ville Oikarinen,
16
Często sam miałem ten problem. Aby uniknąć zależności od małych projektów, często piszę małą funkcję użyteczności, gdy nie potrzebuję wspólnych elementów. Oto kod, aby załadować zawartość pliku do bufora ciągów:
StringBuffer sb =newStringBuffer();BufferedReader br =newBufferedReader(newInputStreamReader(getClass().getResourceAsStream("path/to/textfile.txt"),"UTF-8"));for(int c = br.read(); c !=-1; c = br.read()) sb.append((char)c);System.out.println(sb.toString());
Określenie kodowania jest w tym przypadku ważne, ponieważ mógłbyś edytować plik w UTF-8, a następnie umieścić go w słoiku, a komputer, który otwiera plik, może mieć CP-1251 jako rodzime kodowanie pliku (na przykład) ; więc w tym przypadku nigdy nie znasz kodowania docelowego, dlatego jawne informacje o kodowaniu są kluczowe. Również pętla do odczytu pliku char przez char wydaje się nieefektywna, ale jest używana w BufferedReader, a więc właściwie dość szybko.
Jakie instrukcje importu są potrzebne, aby pobrać klasy „Pliki” i „Ścieżki”?
Steve Scherer
1
oba są częścią pakietu java.nio.file dostępnego w JDK 7+
Raghu K Nair
Nie działa w pliku jar.
Displee
4
Jeśli chcesz pobrać ciąg z zasobu projektu, takiego jak plik testcase / foo.json w pliku src / main / resources w projekcie, wykonaj następujące czynności:
Plik działa tylko dla zasobów ścieżki klasy, które są, no cóż, plikami. Nie, jeśli są elementami w pliku .jar lub częścią grubego słoika, jedną z innych implementacji modułu ładującego klasy.
toolforger
2
Używam następujących do odczytu plików zasobów z classpath:
package test;import java.io.InputStream;import java.nio.charset.StandardCharsets;import java.util.Scanner;publicclassMain{publicstaticvoid main(String[] args){try{String fileContent = getFileFromResources("resourcesFile.txt");System.out.println(fileContent);}catch(Exception e){
e.printStackTrace();}}//USE THIS FUNCTION TO READ CONTENT OF A FILE, IT MUST EXIST IN "RESOURCES" FOLDERpublicstaticString getFileFromResources(String fileName)throwsException{ClassLoader classLoader =Main.class.getClassLoader();InputStream stream = classLoader.getResourceAsStream(fileName);String text =null;try(Scanner scanner =newScanner(stream,StandardCharsets.UTF_8.name())){
text = scanner.useDelimiter("\\A").next();}return text;}}
Przynajmniej od Apache commons-io 2.5 metoda IOUtils.toString () obsługuje argument URI i zwraca zawartość plików znajdujących się w słoikach na ścieżce klas:
Podoba mi się odpowiedź Akosickiego za pomocą Głupiego skanera. Jest to najprostszy, jaki widzę bez zewnętrznych zależności, który działa w Javie 8 (a właściwie aż do Java 5). Oto jeszcze prostsza odpowiedź, jeśli możesz używać języka Java 9 lub nowszego (ponieważ InputStream.readAllBytes()został dodany w języku Java 9):
String text =newString(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());
Skąd pochodzą IOUtils? Źródło powinno być wyraźnie określone.
ehecatl
0
Napisałem tutaj metody readResource () , aby móc to zrobić za pomocą jednego prostego wywołania. To zależy od biblioteki Guava, ale lubię metody tylko JDK sugerowane w innych odpowiedziach i myślę, że zmienię je w ten sposób.
publicclassUtils{publicstaticString readResource(String name)throwsURISyntaxException,IOException{
var uri =Utils.class.getResource("/"+ name).toURI();
var path =Paths.get(uri);returnFiles.readString(path);}}
Lubię narzędzia Apache commons do tego typu rzeczy i używam dokładnie tego przypadku (odczytywanie plików ze ścieżki klas) podczas testowania, szczególnie do odczytywania plików JSON /src/test/resourcesw ramach testów jednostkowych / integracyjnych. na przykład
publicclassFileUtils{publicstaticString getResource(String classpathLocation){try{String message =IOUtils.toString(FileUtils.class.getResourceAsStream(classpathLocation),Charset.defaultCharset());return message;}catch(IOException e){thrownewRuntimeException("Could not read file [ "+ classpathLocation +" ] from classpath", e);}}}
Do celów testowych miło jest złapać IOExceptioni rzucić RuntimeException- Twoja klasa testowa może wyglądać np
@Testpublicvoid shouldDoSomething (){String json =FileUtils.getResource("/json/input.json");// Use json as part of test ...}
Odpowiedzi:
Tak, Guava zapewnia to w
Resources
klasie. Na przykład:źródło
getResource
używa,Resource.class.getClassLoader
ale w aplikacjach internetowych może to nie być „twój” moduł ładujący, więc zaleca się (np. W [1]) użycieThread.currentThread().getContextClassLoader().getResourceAsStream
zamiast tego (odniesienie [1]: stackoverflow.com/questions/676250/… )Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)
co gwarantuje użycie poprawnego modułu ładującego klasy.com.google.common.io.Resources
jest oznaczony jako niestabilny zgodnie z SonarQubeguava
zmienił wdrożenie. W przypadku guava 23 wdrożenie lubi podążać.ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
Możesz użyć starej sztuczki Stupid Scanner oneliner, aby to zrobić bez dodatkowej zależności, takiej jak guava:
Chłopaki, nie używajcie rzeczy innych firm, chyba że naprawdę tego potrzebujecie. JDK ma już wiele funkcji.
źródło
CartApplication.class.getResourceAsStream
abyCartApplication.class.getClassLoader().getResourceAsStream
ładować zasoby w bieżącym słoju .. jak srm / test / resourcesW przypadku java 7:
źródło
getClass().getClassLoader()
ale poza tym świetnego rozwiązania!Czyste i proste, przyjazne dla słoików rozwiązanie Java 8+
Ta prosta metoda poniżej będzie dobrze, jeśli używasz Java 8 lub nowszej:
Działa również z zasobami w plikach jar .
Informacje o kodowaniu tekstu:
InputStreamReader
użyje domyślnego zestawu znaków systemowych, jeśli go nie określisz. Możesz to określić samodzielnie, aby uniknąć problemów z dekodowaniem, takich jak:Unikaj niepotrzebnych zależności
Zawsze wolę nie polegać na dużych, grubych bibliotekach. O ile nie używasz już Guava lub Apache Commons IO do innych zadań, dodanie tych bibliotek do projektu, aby móc czytać z pliku, wydaje się trochę za dużo.
Metoda „prosta”? Chyba żartujesz
Rozumiem, że czysta Java nie wykonuje dobrej roboty, jeśli chodzi o wykonywanie prostych zadań takich jak ten. Na przykład tak czytamy z pliku w Node.js:
Prosty i łatwy do odczytania (chociaż ludzie nadal lubią polegać na wielu zależnościach, głównie z powodu niewiedzy). Lub w Pythonie:
To smutne, ale nadal jest proste w stosunku do standardów Java i wystarczy, że skopiujesz powyższą metodę do swojego projektu i użyjesz jej. Nawet nie proszę o zrozumienie, co się tam dzieje, ponieważ to naprawdę nie ma znaczenia dla nikogo. To po prostu działa, kropka :-)
źródło
InputStream
zmiennais
jest,null
czy nie.Guava ma metodę „toString” do odczytu pliku do ciągu:
Ta metoda nie wymaga, aby plik znajdował się w ścieżce klasy (jak w poprzedniej odpowiedzi Jona Skeeta ).
źródło
String stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
yegor256 znalazł fajne rozwiązanie przy użyciu Apache Commons IO :
źródło
IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8")
.getClassLoader()
do łańcucha metod:String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
apache-commons-io ma nazwę narzędzia
FileUtils
:źródło
Często sam miałem ten problem. Aby uniknąć zależności od małych projektów, często piszę małą funkcję użyteczności, gdy nie potrzebuję wspólnych elementów. Oto kod, aby załadować zawartość pliku do bufora ciągów:
Określenie kodowania jest w tym przypadku ważne, ponieważ mógłbyś edytować plik w UTF-8, a następnie umieścić go w słoiku, a komputer, który otwiera plik, może mieć CP-1251 jako rodzime kodowanie pliku (na przykład) ; więc w tym przypadku nigdy nie znasz kodowania docelowego, dlatego jawne informacje o kodowaniu są kluczowe. Również pętla do odczytu pliku char przez char wydaje się nieefektywna, ale jest używana w BufferedReader, a więc właściwie dość szybko.
źródło
Możesz użyć następującego kodu z Java
źródło
Jeśli chcesz pobrać ciąg z zasobu projektu, takiego jak plik testcase / foo.json w pliku src / main / resources w projekcie, wykonaj następujące czynności:
Zauważ, że w niektórych innych przykładach brakuje metody getClassLoader ().
źródło
Użyj ApUll FileUtils. Ma metodę readFileToString
źródło
Używam następujących do odczytu plików zasobów z
classpath
:Nie są wymagane żadne zależności stron trzecich.
źródło
Dzięki zestawowi importu statycznego rozwiązanie Guava może być bardzo kompaktowym jednowarstwowym:
Wymagany jest następujący import:
źródło
źródło
Przynajmniej od Apache commons-io 2.5 metoda IOUtils.toString () obsługuje argument URI i zwraca zawartość plików znajdujących się w słoikach na ścieżce klas:
źródło
Podoba mi się odpowiedź Akosickiego za pomocą Głupiego skanera. Jest to najprostszy, jaki widzę bez zewnętrznych zależności, który działa w Javie 8 (a właściwie aż do Java 5). Oto jeszcze prostsza odpowiedź, jeśli możesz używać języka Java 9 lub nowszego (ponieważ
InputStream.readAllBytes()
został dodany w języku Java 9):źródło
Guava ma również,
Files.readLines()
jeśli chcesz zwracać wartość jakoList<String>
linia po linii:Zapoznaj się z tutaj, aby porównać 3 sposoby (w
BufferedReader
porównaniu do GuawyFiles
i GuawyResources
) w celu uzyskaniaString
z pliku tekstowego.źródło
Charsets
jest także w Guava. Zobacz: google.github.io/guava/releases/23.0/api/docsOto moje podejście działało dobrze
źródło
Napisałem tutaj metody readResource () , aby móc to zrobić za pomocą jednego prostego wywołania. To zależy od biblioteki Guava, ale lubię metody tylko JDK sugerowane w innych odpowiedziach i myślę, że zmienię je w ten sposób.
źródło
Jeśli dodasz Guava, możesz użyć:
(Inne rozwiązania wspomniały o innej metodzie Guawy, ale są przestarzałe)
źródło
Następujące kody działają dla mnie:
źródło
Oto rozwiązanie wykorzystujące Java 11
Files.readString
:źródło
Stworzyłem metodę statyczną zależną od NO:
źródło
Lubię narzędzia Apache commons do tego typu rzeczy i używam dokładnie tego przypadku (odczytywanie plików ze ścieżki klas) podczas testowania, szczególnie do odczytywania plików JSON
/src/test/resources
w ramach testów jednostkowych / integracyjnych. na przykładDo celów testowych miło jest złapać
IOException
i rzucićRuntimeException
- Twoja klasa testowa może wyglądać npźródło
źródło