101 Stimmen

Wie konvertiert man einen Reader in einen InputStream und einen Writer in einen OutputStream?

Gibt es eine einfache Möglichkeit, Probleme mit der Textkodierung zu vermeiden?

1voto

romeara Punkte 1296

Eine Warnung bei der Verwendung von WriterOutputStream - es nicht immer behandeln das Schreiben von binären Daten in eine Datei richtig / das gleiche wie eine regelmäßige Ausgabe Stream. Ich hatte ein Problem mit dieser, die mich eine Weile auf die Spur zu nehmen nahm.

Wenn Sie können, würde ich empfehlen, einen Ausgabestrom als Basis zu verwenden, und wenn Sie Strings schreiben müssen, verwenden Sie einen OUtputStreamWriter-Wrapper um den Strom zu tun. Es ist weitaus zuverlässiger, Text in Bytes zu konvertieren als umgekehrt, was wahrscheinlich der Grund ist, warum WriterOutputStream nicht Teil der Standard-Java-Bibliothek ist.

0voto

Peter Kriens Punkte 14774

Dies ist der Quellcode für eine einfache UTF-8-basierte Kodierung WriterOutputStream und ReaderInputStream. Getestet am Ende.

    // https://www.woolha.com/tutorials/deno-utf-8-encoding-decoding-examples
    public class WriterOutputStream extends OutputStream {
        final Writer    writer;

        int             count       = 0;
        int             codepoint   = 0;

        public WriterOutputStream(Writer writer) {
            this.writer = writer;
        }

        @Override
        public void write(int b) throws IOException {
            b &= 0xFF;
            switch (b >> 4) {
            case 0b0000:
            case 0b0001:
            case 0b0010:
            case 0b0011:
            case 0b0100:
            case 0b0101:
            case 0b0110:
            case 0b0111:
                count = 1;
                codepoint = b;
                break;

            case 0b1000:
            case 0b1001:
            case 0b1010:
            case 0b1011:
                codepoint <<= 6;
                codepoint |= b & 0b0011_1111;
                break;

            case 0b1100:
            case 0b1101:
                count = 2;
                codepoint = b & 0b0001_1111;
                break;

            case 0b1110:
                count = 3;
                codepoint = b & 0b0000_1111;
                break;

            case 0b1111:
                count = 4;
                codepoint = b & 0b0000_0111;
                break;
            }
            if (--count == 0) {
                writer.write(codepoint);
            }
        }
    }

    public class ReaderInputStream extends InputStream {
        final Reader    reader;
        int             count   = 0;
        int             codepoint;

        public ReaderInputStream(Reader reader) {
            this.reader = reader;
        }

        @Override
        public int read() throws IOException {
            if (count-- > 0) {
                int r = codepoint >> (count * 6);
                r &= 0b0011_1111;
                r |= 0b1000_0000;
                return r;
            }

            codepoint = reader.read();
            if (codepoint < 0)
                return -1;
            if (codepoint > 0xFFFF)
                return 0;

            if (codepoint < 0x80)
                return codepoint;

            if (codepoint < 0x800) {
                count = 1;
                int v = (codepoint >> 6) | 0b1100_0000;
                return v;
            }
            count = 2;
            int v = (codepoint >> 12) | 0b1110_0000;
            return v;
        }
    }

Und der Testfall, der prüft, ob jedes der 65536 Zeichen richtig kodiert und dekodiert ist und ob es mit der Java-Kodierung übereinstimmt. Die Überprüfung der Surrogate (2-Zeichen-Kodierung) wird ignoriert, da dies in Java gehandhabt wird.

    @Test
    public void testAll() throws IOException {
        for (char i = 0; i < 0xFFFF; i++) {
            CharArrayReader car = new CharArrayReader(new char[] { i });
            ReaderInputStream rtoi = new ReaderInputStream(car);
            byte[] data = IO.read(rtoi);

            CharArrayWriter caw = new CharArrayWriter();
            try (WriterOutputStream wtoo = new WriterOutputStream(caw)) {
                wtoo.write(data);
                char[] translated = caw.toCharArray();
                assertThat(translated.length).isEqualTo(1);
                assertThat((int) translated[0]).isEqualTo(i);

                if (!Character.isSurrogate((char) i)) {
                    try (InputStream stream = new ByteArrayInputStream(data)) {
                        caw = new CharArrayWriter();
                        IO.copy(data, caw);
                        translated = caw.toCharArray();
                        assertThat(translated.length).isEqualTo(1);
                        assertThat((int) translated[0]).isEqualTo(i);
                    }
                }
            }
        }
    }

-1voto

Aaron Punkte 844

Für das Lesen einer Zeichenkette in einem Stream wird nur das verwendet, was Java liefert.

InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));

6 Stimmen

ReaderInputStream ist in Apache Commons IO.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X