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.


1
wyjaśnij, co rozumiesz przez „plik tekstowy zasobów” a „plik tekstowy w zasobach” - nie jest łatwo zrozumieć, co próbujesz osiągnąć.
Mat

To tylko plik tekstowy pod ścieżką klasy, taki jak „classpath *: mytext / text.txt”
Loc Phan

Odpowiedzi:


301

Tak, Guava zapewnia to w Resourcesklasie. Na przykład:

URL url = Resources.getResource("foo.txt");
String text = Resources.toString(url, StandardCharsets.UTF_8);

21
@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 = new Scanner(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.


41
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.
Kenny Cason

90

W przypadku java 7:

new String(Files.readAllBytes(Paths.get(getClass().getResource("foo.txt").toURI())));

3
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
 */
static String getResourceFileAsString(String fileName) throws IOException {
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    try (InputStream is = classLoader.getResourceAsStream(fileName)) {
        if (is == null) return null;
        try (InputStreamReader isr = new InputStreamReader(is);
             BufferedReader reader = new BufferedReader(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:

new InputStreamReader(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:

const fs = require("fs");
const contents = fs.readFileSync("some-file.txt", "utf-8");

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 :-)


4
@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:

import com.google.common.base.Charsets;
import com.google.common.io.Files;

String content = Files.toString(new File("/home/x1/text.log"), Charsets.UTF_8);

Ta metoda nie wymaga, aby plik znajdował się w ścieżce klasy (jak w poprzedniej odpowiedzi Jona Skeeta ).


2
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"));
Eran Medan

1
Jest to przestarzałe w Guava 24.1
Andrey

47

yegor256 znalazł fajne rozwiązanie przy użyciu Apache Commons IO :

import org.apache.commons.io.IOUtils;

String text = IOUtils.toString(this.getClass().getResourceAsStream("foo.xml"),
                               "UTF-8");

Wolę „” niż w przypadku, gdy jest to niedostępne
833970 15.01.15

11
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);
Abdull

39

apache-commons-io ma nazwę narzędzia FileUtils:

URL url = Resources.getResource("myFile.txt");
File myFile = new File(url.toURI());

String content = FileUtils.readFileToString(myFile, "UTF-8");  // or any other encoding

1
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.
Feuermurmel

Apache fileutils . readLines (plik) i copyURLToFile (URL, tempFile).
Yash,

2
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 = new StringBuffer();

BufferedReader br = new BufferedReader(new InputStreamReader(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.


15

Możesz użyć następującego kodu z Java

new String(Files.readAllBytes(Paths.get(getClass().getResource("example.txt").toURI())));

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:

String myString= 
 new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("testcase/foo.json").toURI())));

Zauważ, że w niektórych innych przykładach brakuje metody getClassLoader ().


2

Użyj ApUll FileUtils. Ma metodę readFileToString


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:

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Scanner;

public class ResourceUtilities
{
    public static String resourceToString(String filePath) throws IOException, URISyntaxException
    {
        try (InputStream inputStream = ResourceUtilities.class.getClassLoader().getResourceAsStream(filePath))
        {
            return inputStreamToString(inputStream);
        }
    }

    private static String inputStreamToString(InputStream inputStream)
    {
        try (Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"))
        {
            return scanner.hasNext() ? scanner.next() : "";
        }
    }
}

Nie są wymagane żadne zależności stron trzecich.


1

Dzięki zestawowi importu statycznego rozwiązanie Guava może być bardzo kompaktowym jednowarstwowym:

toString(getResource("foo.txt"), UTF_8);

Wymagany jest następujący import:

import static com.google.common.io.Resources.getResource
import static com.google.common.io.Resources.toString
import static java.nio.charset.StandardCharsets.UTF_8

1
package test;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Main {
    public static void 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" FOLDER
    public static String getFileFromResources(String fileName) throws Exception {
        ClassLoader classLoader = Main.class.getClassLoader();
        InputStream stream = classLoader.getResourceAsStream(fileName);
        String text = null;
        try (Scanner scanner = new Scanner(stream, StandardCharsets.UTF_8.name())) {
            text = scanner.useDelimiter("\\A").next();
        }
        return text;
    }
}

1

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:

IOUtils.toString(SomeClass.class.getResource(...).toURI(), ...)

1

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 = new String(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());

0

Guava ma również, Files.readLines()jeśli chcesz zwracać wartość jako List<String>linia po linii:

List<String> lines = Files.readLines(new File("/file/path/input.txt"), Charsets.UTF_8);

Zapoznaj się z tutaj, aby porównać 3 sposoby (w BufferedReaderporównaniu do Guawy Filesi Guawy Resources) w celu uzyskania Stringz pliku tekstowego.


Co to jest klasa Charsets? nie jest natywny
e-info128 17.09.17

@ e-info128 Charsetsjest także w Guava. Zobacz: google.github.io/guava/releases/23.0/api/docs
philipjkim

0

Oto moje podejście działało dobrze

public String getFileContent(String fileName) {
    String filePath = "myFolder/" + fileName+ ".json";
    try(InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath)) {
        return IOUtils.toString(stream, "UTF-8");
    } catch (IOException e) {
        // Please print your Exception
    }
}

2
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.


0

Jeśli dodasz Guava, możesz użyć:

String fileContent = Files.asCharSource(new File(filename), Charset.forName("UTF-8")).read();

(Inne rozwiązania wspomniały o innej metodzie Guawy, ale są przestarzałe)


0

Następujące kody działają dla mnie:

compile group: 'commons-io', name: 'commons-io', version: '2.6'

@Value("classpath:mockResponse.json")
private Resource mockResponse;

String mockContent = FileUtils.readFileToString(mockResponse.getFile(), "UTF-8");

0

Oto rozwiązanie wykorzystujące Java 11 Files.readString:

public class Utils {
    public static String readResource(String name) throws URISyntaxException, IOException {
        var uri = Utils.class.getResource("/" + name).toURI();
        var path = Paths.get(uri);
        return Files.readString(path);
    }
}

0

Stworzyłem metodę statyczną zależną od NO:

import java.nio.file.Files;
import java.nio.file.Paths;

public class ResourceReader {
    public  static String asString(String resourceFIleName) {
        try  {
            return new String(Files.readAllBytes(Paths.get(new CheatClassLoaderDummyClass().getClass().getClassLoader().getResource(resourceFIleName).toURI())));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
class CheatClassLoaderDummyClass{//cheat class loader - for sql file loading
}

0

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

public class FileUtils {

    public static String getResource(String classpathLocation) {
        try {
            String message = IOUtils.toString(FileUtils.class.getResourceAsStream(classpathLocation),
                    Charset.defaultCharset());
            return message;
        }
        catch (IOException e) {
            throw new RuntimeException("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

    @Test
    public void shouldDoSomething () {
        String json = FileUtils.getResource("/json/input.json");

        // Use json as part of test ...
    }

-2
public static byte[] readResoureStream(String resourcePath) throws IOException {
    ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
    InputStream in = CreateBffFile.class.getResourceAsStream(resourcePath);

    //Create buffer
    byte[] buffer = new byte[4096];
    for (;;) {
        int nread = in.read(buffer);
        if (nread <= 0) {
            break;
        }
        byteArray.write(buffer, 0, nread);
    }
    return byteArray.toByteArray();
}

Charset charset = StandardCharsets.UTF_8;
String content = new   String(FileReader.readResoureStream("/resource/...*.txt"), charset);
String lines[] = content.split("\\n");

Dodaj krótkie wyjaśnienie do swojej odpowiedzi.
Nikolay Mihaylov,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.