Próbowałem użyć java.io.FileReader do odczytania niektórych plików tekstowych i przekonwertowania ich na ciąg, ale okazało się, że wynik jest nieprawidłowo zakodowany i w ogóle nie jest czytelny.
Oto moje środowisko:
Windows 2003, kodowanie systemu operacyjnego: CP1252
Java 5.0
Moje pliki są zakodowane w UTF-8 lub CP1252, a niektóre z nich (pliki zakodowane w UTF-8) mogą zawierać znaki chińskie (inne niż łacińskie).
Do pracy używam następującego kodu:
private static String readFileAsString(String filePath)
throws java.io.IOException{
StringBuffer fileData = new StringBuffer(1000);
FileReader reader = new FileReader(filePath);
//System.out.println(reader.getEncoding());
BufferedReader reader = new BufferedReader(reader);
char[] buf = new char[1024];
int numRead=0;
while((numRead=reader.read(buf)) != -1){
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
}
reader.close();
return fileData.toString();
}
Powyższy kod nie działa. Odkryłem, że kodowanie FileReadera to CP1252, nawet jeśli tekst jest zakodowany w UTF-8. Ale JavaDoc z java.io.FileReader mówi, że:
Konstruktorzy tej klasy zakładają, że domyślne kodowanie znaków i domyślny rozmiar buforu bajtów są odpowiednie.
Czy to oznacza, że nie muszę samodzielnie ustawiać kodowania znaków, jeśli używam FileReader? Ale obecnie otrzymałem błędnie zakodowane dane. Jaki jest właściwy sposób radzenia sobie z moją sytuacją? Dzięki.
Odpowiedzi:
Tak, musisz określić kodowanie pliku, który chcesz przeczytać.
Tak, oznacza to, że musisz znać kodowanie pliku, który chcesz przeczytać.
Nie, nie ma ogólnego sposobu na odgadnięcie kodowania dowolnego pliku „zwykłego tekstu”.
Konstruktory jednargumentowe
FileReader
zawsze używają domyślnego kodowania platformy, co jest ogólnie złym pomysłem .Od Java 11
FileReader
zyskały również konstruktory akceptujące kodowanie:new FileReader(file, charset)
inew FileReader(fileName, charset)
.We wcześniejszych wersjach java musisz użyć .
new InputStreamReader(
new FileInputStream(pathToFile)
, <encoding>)
źródło
InputStreamReader
jest tojava.io
klasa, to będzie to „UTF8”?StandardCharsets.UTF_8
, nie ma tam szans na pomyłkę ;-) Ale tak, jeśli pójdziesz ze stringiem,"UTF8"
będzie to poprawne (chociaż wydaje mi się, że pamiętam, że zaakceptuje obie strony).Byte Order Mark
, wraz z… cóż… ustaleniem kolejności bajtów! :) W związku z tym wydaje mi się dziwne, że FileReader Javy nie jest w stanie automatycznie wykryć UTF-16, który ma taki BOM ... Właściwie kiedyś napisałem taki,UnicodeFileReader
który robi dokładnie to. Niestety zamknięte źródło, ale Google ma swój UnicodeReader, który jest bardzo podobny.FileReader
używa domyślnego kodowania platformy Java, które zależy od ustawień systemowych komputera, na którym działa i jest ogólnie najpopularniejszym kodowaniem wśród użytkowników w tym regionie.Jeśli to „najlepsze przypuszczenie” nie jest poprawne, musisz jawnie określić kodowanie. Niestety
FileReader
nie pozwala na to (duży niedopatrzenie w API). Zamiast tego musisz użyćnew InputStreamReader(new FileInputStream(filePath), encoding)
i najlepiej uzyskać kodowanie z metadanych dotyczących pliku.źródło
FileReader
wykorzystuje domyślne kodowanie platformy Java, które zależy od ustawień systemowych komputera, na którym jest uruchomiony, i jest generalnie najpopularniejszym kodowaniem wśród użytkowników w tym regionie”. Nie powiedziałbym tego. Przynajmniej Windows. Z pewnych dziwnych technicznych / historycznych powodów JVM ignoruje fakt, że Unicode jest zalecanym kodowaniem w systemie Windows dla „wszystkich nowych aplikacji” i zamiast tego zawsze zachowuje się tak, jakby starsze kodowanie skonfigurowane jako rezerwowe dla starszych aplikacji było „domyślną platformą”.Od wersji Java 11 możesz tego używać:
public FileReader(String fileName, Charset charset) throws IOException;
źródło
W przypadku dokumentu Java 7+ możesz użyć tego:
Oto wszystkie dokumenty dotyczące Charsets
Na przykład, jeśli twój plik jest w CP1252, użyj tej metody
Charset.forName("windows-1252");
Oto inne nazwy kanoniczne dla Java kodowania zarówno do IO i NIO doc
Jeśli nie wiesz dokładnie z kodowania masz w pliku, można używać niektórych bibliotekami innych firm jak tego narzędzia od Google ten , który działa dość schludny.
źródło
FileInputStream z InputStreamReader jest lepszy niż bezpośrednie używanie FileReader, ponieważ ten ostatni nie pozwala na określenie zestawu kodowania.
Oto przykład użycia razem BufferedReader, FileInputStream i InputStreamReader, abyś mógł czytać wiersze z pliku.
List<String> words = new ArrayList<>(); List<String> meanings = new ArrayList<>(); public void readAll( ) throws IOException{ String fileName = "College_Grade4.txt"; String charset = "UTF-8"; BufferedReader reader = new BufferedReader( new InputStreamReader( new FileInputStream(fileName), charset)); String line; while ((line = reader.readLine()) != null) { line = line.trim(); if( line.length() == 0 ) continue; int idx = line.indexOf("\t"); words.add( line.substring(0, idx )); meanings.add( line.substring(idx+1)); } reader.close(); }
źródło
Dla innych języków łacińskich, na przykład cyrylicy, możesz użyć czegoś takiego:
FileReader fr = new FileReader("src/text.txt", StandardCharsets.UTF_8);
i upewnij się, że
.txt
plik został zapisany w formacieUTF-8
(ale nie jako domyślnyANSI
). Twoje zdrowie!źródło