Czy istnieje łatwy sposób na uniknięcie problemów z kodowaniem tekstu?
87
Naprawdę nie możesz uniknąć problemów z kodowaniem tekstu, ale istnieją rozwiązania w Apache Commons:
Reader
do InputStream
:ReaderInputStream
Writer
do OutputStream
:WriterOutputStream
Musisz tylko wybrać wybrane przez siebie kodowanie.
Jeśli zaczynasz od String, możesz również wykonać następujące czynności:
new ByteArrayInputStream(inputString.getBytes("UTF-8"))
źródło
ReaderInputStream
implementacja wymagałaby mniej pamięci - nie powinno być potrzeby jednoczesnego przechowywania wszystkich bajtów w tablicy.Cóż, Reader zajmuje się znakami, a InputStream zajmuje się bajtami. Kodowanie określa, w jaki sposób chcesz przedstawić swoje znaki jako bajty, więc nie możesz tak naprawdę zignorować problemu. Jeśli chodzi o unikanie problemów, moim zdaniem: wybierz jeden zestaw znaków (np. „UTF-8”) i trzymaj się go.
Jeśli chodzi o to, jak to zrobić, jak wskazano, „ oczywistymi nazwami tych klas są ReaderInputStream i WriterOutputStream . ” Co zaskakujące, „ nie są one zawarte w bibliotece Java ”, mimo że „przeciwne” klasy, InputStreamReader i OutputStreamWriter są w zestawie.
Tak więc wiele osób wymyśliło własne implementacje, w tym Apache Commons IO . W zależności od kwestii licencyjnych prawdopodobnie będziesz w stanie włączyć bibliotekę commons-io do swojego projektu, a nawet skopiować część kodu źródłowego (który można pobrać tutaj ).
Jak widać, dokumentacja obu klas stwierdza, że „wszystkie kodowania zestawów znaków obsługiwane przez środowisko JRE są obsługiwane poprawnie”.
Uwaga: komentarz do jednej z pozostałych odpowiedzi wspomina o tym błędzie . Ma to jednak wpływ na klasę Apache Ant ReaderInputStream ( tutaj ), a nie na klasę Apache Commons IO ReaderInputStream.
źródło
Zauważ również, że jeśli zaczynasz od String, możesz pominąć tworzenie StringReader i utworzyć InputStream w jednym kroku, używając org.apache.commons.io.IOUtils z Commons IO, tak jak to:
InputStream myInputStream = IOUtils.toInputStream(reportContents, "UTF-8");
Oczywiście nadal musisz pomyśleć o kodowaniu tekstu, ale przynajmniej konwersja odbywa się w jednym kroku.
źródło
new ByteArrayInputStream(report.toString().getBytes("utf-8"))
polega na przydzieleniu dwóch dodatkowych kopii raportu w pamięci. Jeśli raport jest obszerny, jest zły. Zobacz moją odpowiedź.Posługiwać się:
new CharSequenceInputStream(html, StandardCharsets.UTF_8);
W ten sposób nie wymaga wcześniejszej konwersji na,
String
a następnie nabyte[]
, co przydziela dużo więcej pamięci sterty na wypadek, gdyby raport był duży. Konwertuje na bajty w locie, gdy strumień jest odczytywany, bezpośrednio z StringBuffer.Używa CharSequenceInputStream z projektu Apache Commons IO.
źródło
commons-io 2.0 ma
WriterOutputStream
źródło
Oczywiste nazwy tych klas to ReaderInputStream i WriterOutputStream. Niestety nie są one zawarte w bibliotece Java. Jednak Google to twój przyjaciel.
Nie jestem pewien, czy obejdzie wszystkie problemy z kodowaniem tekstu, które są koszmarne.
Istnieje RFE, ale jest zamknięty, nie naprawi.
źródło
Nie możesz uniknąć problemów z kodowaniem tekstu, ale Apache commons-io tak
Zwróć uwagę, że są to biblioteki, do których odnosi się odpowiedź Piotra na koders.com, a jedynie łącza do biblioteki zamiast kodu źródłowego.
źródło
Czy próbujesz zapisać zawartość od a
Reader
do anOutputStream
? Jeśli tak, łatwiej będzie ci zawinąćOutputStream
w anOutputStreamWriter
i zapisaćchar
s od theReader
doWriter
, zamiast próbować przekonwertować czytnik naInputStream
:final Writer writer = new BufferedWriter(new OutputStreamWriter( urlConnection.getOutputStream(), "UTF-8" ) ); int charsRead; char[] cbuf = new char[1024]; while ((charsRead = data.read(cbuf)) != -1) { writer.write(cbuf, 0, charsRead); } writer.flush(); // don't forget to close the writer in a finally {} block
źródło
Ostrzeżenie podczas korzystania z WriterOutputStream - nie zawsze obsługuje poprawnie zapisywanie danych binarnych do pliku / tak samo jak zwykły strumień wyjściowy. Miałem z tym problem, którego wytropienie zajęło mi trochę czasu.
Jeśli możesz, polecam użycie strumienia wyjściowego jako podstawy, a jeśli chcesz napisać ciągi, użyj otoki OUtputStreamWriter wokół strumienia, aby to zrobić. O wiele bardziej niezawodne jest przekonwertowanie tekstu na bajty niż na odwrót, co prawdopodobnie powoduje, że WriterOutputStream nie jest częścią standardowej biblioteki Java
źródło
Możesz użyć Cactoos (bez metod statycznych, tylko obiekty):
new InputStreamOf(reader)
new OutputStreamTo(writer)
Możesz konwertować również na odwrót:
new ReaderOf(inputStream)
new WriterTo(outputStream)
źródło
Do czytania łańcucha w strumieniu przy użyciu tego, co dostarcza Java.
InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));
źródło