Czytanie InputStream jako UTF-8

96

Próbuję czytać z text/plainpliku przez Internet, wiersz po wierszu. Kod, który mam teraz, to:

URL url = new URL("http://kuehldesign.net/test.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
LinkedList<String> lines = new LinkedList();
String readLine;

while ((readLine = in.readLine()) != null) {
    lines.add(readLine);
}

for (String line : lines) {
    out.println("> " + line);
}

Plik test.txtzawiera ¡Hélló!, którego używam do testowania kodowania.

Kiedy przeglądam OutputStream( out), widzę to jako > ¬°H√©ll√≥!. Nie wierzę, że jest to problem z tym, OutputStreamponieważ mogę się obejść out.println("é");bez problemów.

Jakieś pomysły na odczytanie InputStreamjako UTF-8? Dzięki!

Chris Kuehl
źródło
1
Protokół HTTP określa kodowanie. Dlaczego nie używasz interfejsu API biblioteki, który obsługuje to za Ciebie? Nigdy nie powinieneś zgadywać takiego kodowania. Nie chcę być negatywny: radzisz sobie świetnie! Zastanawiam się tylko, czy nie ma łatwiejszego sposobu.
tchrist
1
Nie będę miał text/plainniestety dostępu do serwera, który udostępnia plik i nie używa on kodowania UTF-8. Nie znałem żadnych dobrych bibliotek sieciowych; jakieś sugestie?
Chris Kuehl,
1
Patrząc na dokumenty , nie sądziłbym , że w ogóle będziesz musiał określać kodowanie. Jestem zaskoczony, że dają ci strumień bajtów! Masz dostęp do bazowego połączenia URL , z którego możesz sprawdzić kodowanie zawartości, a następnie otworzyć InputStreamReader z odpowiednim argumentem. Szybkie sprawdzenie źródła nie ujawnia niczego, co wydaje się robić to za Ciebie, co wydaje się cholernie kiepskie i podatne na błędy, więc prawdopodobnie coś przeoczyłem.
tchrist

Odpowiedzi:

189

Rozwiązałem własny problem. Ta linia:

BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));

musi być:

BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));

lub od wersji Java 7:

BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8));
Chris Kuehl
źródło
3
Jestem prawie pewien, że ta forma konstruktora nie zgłosi wyjątku w przypadku nieprawidłowych danych wejściowych. Musisz użyć CharsetDecoder decargumentu. To ten sam błąd projektowy Javy, który OutputStreamWritermają konstruktorzy: tylko jeden z czterech w rzeczywistości protekcjonalnie mówi ci, kiedy coś pójdzie nie tak. CharsetDecoder decTam również musisz użyć fantazyjnego argumentu. Jedyną bezpieczną i rozsądną rzeczą do zrobienia jest uznanie wszystkich innych konstruktorów za przestarzałe, ponieważ nie można im ufać, że zachowują się.
tchrist
6
Od wersji Java 7 możliwe jest zapisanie StandardCharsets.UTF_8
zestawu znaków
18
String file = "";

try {

    InputStream is = new FileInputStream(filename);
    String UTF8 = "utf8";
    int BUFFER_SIZE = 8192;

    BufferedReader br = new BufferedReader(new InputStreamReader(is,
            UTF8), BUFFER_SIZE);
    String str;
    while ((str = br.readLine()) != null) {
        file += str;
    }
} catch (Exception e) {

}

Spróbuj tego,.. :-)

Rohith
źródło
8
Zamiast file + = str, utwórz StringBuilder i dołącz do niego. Kompilator może być w stanie zoptymalizować dołączanie ciągu, ale prawdopodobnie tworzy dużo śmieci
patrz
2
Jeśli chcesz przekonwertować BufferedReader na ciąg, użyj Apache Commons, nie wymyślaj na nowo kołka: String myStr = org.apache.commons.io.IOUtils.toString (myBufferedReaderInstance);
Jaime Marín
8
UTF8 = "utf8", ładna zmienna;)
Nicofisi,
7

Napotykałem ten sam problem za każdym razem, gdy znajdował specjalny znak oznaczający go jako . aby rozwiązać ten problem, próbowałem użyć kodowania: ISO-8859-1

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("txtPath"),"ISO-8859-1"));

while ((line = br.readLine()) != null) {

}

Mam nadzieję, że pomoże to każdemu, kto zobaczy ten post.

joshua cleveland
źródło
1
Czy mógłbyś powiedzieć, jakie znaki nie są obsługiwane w UTF-8?
USM