Od jakiegoś czasu używam poniższego idiomu. I wydaje się być najbardziej rozpowszechniony, przynajmniej w witrynach, które odwiedziłem.
Czy jest lepszy / inny sposób wczytywania pliku do łańcucha w Javie?
private String readFile(String file) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader (file));
String line = null;
StringBuilder stringBuilder = new StringBuilder();
String ls = System.getProperty("line.separator");
try {
while((line = reader.readLine()) != null) {
stringBuilder.append(line);
stringBuilder.append(ls);
}
return stringBuilder.toString();
} finally {
reader.close();
}
}
byte[] Files.readAllBytes(file);
tym, którzy sugerują skaner „jednowierszowy”: czy nie musisz go zamykać?Odpowiedzi:
Przeczytaj cały tekst z pliku
Java 11 dodała metodę readString () do odczytu małych plików jako
String
, zachowując terminatory linii:Dla wersji między Java 7 a 11, oto kompaktowy, solidny idiom zawarty w metodzie narzędziowej:
Czytaj wiersze tekstu z pliku
Java 7 dodała wygodną metodę odczytu pliku jako wiersza tekstu reprezentowanego jako
List<String>
. To podejście jest „stratne”, ponieważ separatory linii są usuwane z końca każdej linii.Java 8 dodała
Files.lines()
metodę tworzeniaStream<String>
. Ponownie, ta metoda jest stratna, ponieważ separatory linii są usuwane. JeśliIOException
podczas odczytu pliku zostanie napotkany, jest on zawijany wUncheckedIOException
, ponieważStream
nie akceptuje lambd, które zgłaszają sprawdzone wyjątki.To
Stream
wymagaclose()
połączenia; jest to słabo udokumentowane w interfejsie API i podejrzewam, że wiele osób nawet nie zauważa, żeStream
maclose()
metodę. Pamiętaj, aby użyć bloku ARM, jak pokazano.Jeśli pracujesz ze źródłem innym niż plik, możesz zamiast tego użyć
lines()
metodyBufferedReader
Wykorzystanie pamięci
Pierwsza metoda, która zachowuje podział wiersza, może tymczasowo wymagać pamięci kilkakrotnie większej niż rozmiar pliku, ponieważ przez krótki czas surowa zawartość pliku (tablica bajtów) i zdekodowane znaki (z których każdy ma 16 bitów, nawet jeśli jest zakodowany 8 plików w pliku) znajdują się jednocześnie w pamięci. Najbezpieczniej jest zastosować do plików, o których wiadomo, że są małe w stosunku do dostępnej pamięci.
Druga metoda, czytanie linii, jest zwykle bardziej wydajna pod względem pamięci, ponieważ bufor bajtów wejściowych do dekodowania nie musi zawierać całego pliku. Jednak nadal nie nadaje się do plików, które są bardzo duże w stosunku do dostępnej pamięci.
Do odczytu dużych plików potrzebujesz innego projektu dla swojego programu, który odczytuje fragment tekstu ze strumienia, przetwarza go, a następnie przechodzi do następnego, ponownie wykorzystując ten sam blok pamięci o stałej wielkości. Tutaj „duży” zależy od specyfikacji komputera. Obecnie ten próg może wynosić wiele gigabajtów pamięci RAM. Trzecia metoda, przy użyciu a,
Stream<String>
jest jednym ze sposobów, aby to zrobić, jeśli twoje wejściowe „rekordy” są przypadkami pojedynczych linii. (ZastosowaniereadLine()
metodyBufferedReader
jest proceduralnym odpowiednikiem tego podejścia).Kodowanie znaków
Jednej rzeczy, której brakuje w próbce w oryginalnym poście, jest kodowanie znaków. Istnieją pewne szczególne przypadki, w których domyślna platforma jest tym, czego chcesz, ale są one rzadkie i powinieneś być w stanie uzasadnić swój wybór.
StandardCharsets
Klasa zdefiniowanie pewnych stałych dla kodowania wymagane od wszystkich środowisk wykonawczych Java:Domyślna platforma jest dostępna w
Charset
samej klasie :Uwaga: ta odpowiedź w dużej mierze zastępuje moją wersję Java 6. Narzędzie Java 7 bezpiecznie upraszcza kod, a stara odpowiedź, która używała odwzorowanego bufora bajtów, uniemożliwiała usunięcie odczytanego pliku, dopóki zmapowany bufor nie został wyrzucony. Możesz wyświetlić starą wersję za pomocą linku „edytowanego” w tej odpowiedzi.
źródło
FileChannel#map
to, że zasadniczo nie nadaje się do użytku.Jeśli chcesz korzystać z zewnętrznej biblioteki, sprawdź Apache Commons IO (200 KB JAR). Zawiera
org.apache.commons.io.FileUtils.readFileToString()
metodę, która pozwala wczytać całośćFile
doString
jednego wiersza kodu.Przykład:
źródło
Bardzo oszczędne rozwiązanie oparte na
Scanner
:Lub, jeśli chcesz ustawić zestaw znaków:
Lub z blokiem try-with-resources , który woła
scanner.close()
cię:Pamiętaj, że
Scanner
konstruktor może wyrzucićIOException
. I nie zapomnij zaimportowaćjava.io
ijava.util
.Źródło: blog Pat Niemeyer
źródło
java.util.NoSuchElementException
.od wersji Java 7 możesz to zrobić w ten sposób.
źródło
Jeśli szukasz alternatywy, która nie wymaga biblioteki innej firmy (np Commons I / O ), możesz użyć klasy Scanner :
źródło
Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));
. W przeciwnym razie możesz przechwycić tylko część pliku.Guawa ma metodę podobną do tej z Commons IOUtils, o której wspominał Willi aus Rohr:
Edycja przez PiggyPiglet
Files#toString
jest przestarzała i należy ją usunąć Octobor 2019. Zamiast tego użyjFiles.asCharSource(new File(path), StandardCharsets.UTF_8).read();
EDYCJA Oscara Reyesa
Oto (uproszczony) podstawowy kod cytowanej biblioteki:
Edycja (autor: Jonik): Powyższe nie pasuje do kodu źródłowego najnowszych wersji Guava. Bieżące źródło znajduje się w klasach Pliki , CharStreams , ByteSource i CharSource w pakiecie com.google.common.io .
źródło
Closer
w CharSource . Kod w odpowiedzi nie jest faktycznym, aktualnym źródłem guawy........
źródło
new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));
new String(Files.readAllBytes(Paths.get(filename)));
:-)Paths
widocznie 1.7+ jak jestFileSystems
. (Cholera!)Jeśli potrzebujesz przetwarzania łańcucha (przetwarzanie równoległe), Java 8 ma świetne API Stream.
Więcej przykładów dostępnych jest w przykładach JDK,
sample/lambda/BulkDataOperations
które można pobrać ze strony pobierania Oracle Java SE 8Kolejny przykład liniowej
źródło
Ten kod normalizuje podział wiersza, który może, ale nie musi być tym, co naprawdę chcesz zrobić.
Oto alternatywa, która tego nie robi i która jest (IMO) prostsza do zrozumienia niż kod NIO (chociaż nadal używa
java.nio.charset.Charset
):źródło
Zebrano wszystkie możliwe sposoby odczytu pliku jako ciągu z dysku lub sieci.
Guawa: Google za pomocą klas
Resources
,Files
APACHE - WSPÓLNE IO za pomocą klas IOUtils, FileUtils
Java 8 BufferReader przy użyciu Stream API
Klasa skanera z wyrażeniem regularnym
\A
. który pasuje do początku danych wejściowych.Java 7 (
java.nio.file.Files.readAllBytes
)BufferedReader
za pomocąInputStreamReader
.Przykład z główną metodą dostępu do powyższych metod.
@widzieć
źródło
Jeśli jest to plik tekstowy, dlaczego nie użyć apache commons-io ?
Ma następującą metodę
Jeśli chcesz linie jako listę, użyj
źródło
Od JDK 11:
źródło
Aby odczytać plik jako plik binarny i przekonwertować na końcu
źródło
W Javie 7 jest to moja preferowana opcja odczytu pliku UTF-8:
Od wersji Java 7 JDK ma nowy
java.nio.file
interfejs API, który zapewnia wiele skrótów, więc biblioteki innych firm nie zawsze są wymagane do prostych operacji na plikach.źródło
Java stara się być bardzo ogólna i elastyczna we wszystkim, co robi. W rezultacie coś, co jest stosunkowo proste w języku skryptowym (twój kod zostałby zastąpiony przez „
open(file).read()
” w pythonie) jest o wiele bardziej skomplikowane. Wydaje się, że nie ma krótszego sposobu na zrobienie tego, z wyjątkiem korzystania z zewnętrznej biblioteki (jak wspomniano Willi aus Rohr ). Twoje opcje:Twój najlepszy zakład to prawdopodobnie drugi, ponieważ ma najmniej zależności.
źródło
byte[] bytes = Files.readAllBytes(someFile.toPath());
Przy użyciu JDK 8 lub nowszej:
brak bibliotek zewnętrznych
Możesz utworzyć nowy obiekt String z zawartości pliku (Korzystanie z klas z
java.nio.file
pakietu):źródło
Istnieje wariant tego samego motywu, który używa pętli for zamiast pętli while, aby ograniczyć zakres zmiennej liniowej. To, czy jest „lepiej”, zależy od osobistego gustu.
źródło
line
zmiennej. Edycja zadeklarowała to dwukrotnie, co byłoby błędem kompilacji.Jeśli nie masz dostępu do
Files
klasy, możesz użyć rozwiązania natywnego.źródło
Elastyczne rozwiązanie wykorzystujące IOUtils z Apache commons-io w połączeniu z StringWriter :
Działa z dowolnym czytnikiem lub strumieniem wejściowym (nie tylko z plikami), na przykład podczas czytania z adresu URL.
źródło
Należy pamiętać, że użycie
fileInputStream.available()
zwracanej liczby całkowitej nie musi reprezentować rzeczywistego rozmiaru pliku, ale raczej odgadniętą liczbę bajtów, którą system powinien móc odczytać ze strumienia bez blokowania IO. Bezpieczny i prosty sposób może wyglądać takNależy wziąć pod uwagę, że to podejście nie jest odpowiednie dla kodowania znaków wielobajtowych, takich jak UTF-8.
źródło
available()
metodzie, nie ma gwarancji, że koniec pliku zostanie osiągnięty w przypadku, metoda zwraca 0. W takim wypadku może skończyć się z niekompletnego pliku. Co gorsza, liczba faktycznie odczytanych bajtów może być mniejsza niż wartość zwracana przezavailable()
, w którym to przypadku otrzymujesz uszkodzone dane wyjściowe.Ten używa metody
RandomAccessFile.readFully
, wydaje się być dostępny z JDK 1.0!źródło
Możesz wypróbować skaner i klasę plików, rozwiązanie kilku linii
źródło
Użytkownik
java.nio.Files
odczytuje wszystkie wiersze pliku.źródło
źródło
cannot find symbol
.Nie mogę jeszcze komentować innych wpisów, więc zostawię to tutaj.
Jedna z najlepszych odpowiedzi tutaj ( https://stackoverflow.com/a/326448/1521167 ):
wciąż ma jedną wadę. Zawsze umieszcza znak nowej linii na końcu łańcucha, co może powodować pewne dziwne błędy. Moja sugestia to zmienić to na:
źródło
Po Ctrl + F'ing po skanerze, myślę, że rozwiązanie skanera również powinno zostać wymienione. W najłatwiejszy do odczytania sposób wygląda to tak:
Jeśli używasz Java 7 lub nowszej (i naprawdę powinieneś), rozważ użycie try-with-resources, aby ułatwić odczytanie kodu. Nigdy więcej zaśmiecania wszystkiego zaśmiecaniem. Ale to głównie wybór stylistyczny.
Zamieszczam to głównie dla uzupełnienia, ponieważ jeśli musisz to robić dużo, powinny być rzeczy Zamieszczam pliku java.nio.file.Files które powinny lepiej wykonywać tę pracę.
Moją sugestią byłoby użycie plików # readAllBytes (ścieżka), aby pobrać wszystkie bajty i podać je do nowego ciągu (zestaw znaków bajt []) zestaw aby uzyskać z niego ciąg, któremu można zaufać. Zestawy znaków będą dla ciebie wredne przez całe życie, więc uważaj teraz na te rzeczy.
Inni podali kod i inne rzeczy, a ja nie chcę kraść ich chwały. ;)
źródło
Korzystając z tej biblioteki , jest to jedna linia:
źródło
Również jeśli plik znajduje się w słoiku, możesz również użyć tego:
Ścieżka powinna zaczynać się
/
na przykład od słoikaNastępnie chcesz wywołać to w ten sposób:
źródło
W jednym wierszu (Java 8), zakładając, że masz czytnik:
źródło
Na podstawie odpowiedzi @ erickson możesz użyć:
źródło