Czy istnieje łatwy sposób na uniknięcie problemów z kodowaniem tekstu?
Czy istnieje łatwy sposób na uniknięcie problemów z kodowaniem tekstu?
Odpowiedzi:
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"))
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.
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.
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.
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.
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.
Czy próbujesz zapisać zawartość od a Reader
do an OutputStream
? Jeśli tak, łatwiej będzie ci zawinąć OutputStream
w an OutputStreamWriter
i zapisać char
s od the Reader
do Writer
, zamiast próbować przekonwertować czytnik na InputStream
:
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
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
Możesz użyć Cactoos (bez metod statycznych, tylko obiekty):
Możesz konwertować również na odwrót:
Do czytania łańcucha w strumieniu przy użyciu tego, co dostarcza Java.
InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));