Як перетворити Reader на InputStream, а Writer на OutputStream?


Відповіді:


45

Ви дійсно не можете уникнути вирішення питань кодування тексту, але в Apache Commons є існуючі рішення:

Вам просто потрібно вибрати кодування на ваш вибір.


7
FYI: код ReaderInputStream має помилку в способі читання байтів (він не працюватиме для всіх кодувань). Доказ: illegalargumentexception.blogspot.com/2009/05/… Існує відкрита помилка: issues.apache.org/bugzilla/show_bug.cgi?id=40455
Макдауелл,

1
Ви можете знайти класи в бібліотеці commons-io Apache: commons.apache.org/proper/commons-io
AlikElzin-kilaka

@McDowell, помилка, про яку ви згадали, полягає у реалізації Apache Ant, а не в commons-io, тому вона не має значення для цієї відповіді.
Роман

94

Якщо ви починаєте з рядка, ви також можете зробити наступне:

new ByteArrayInputStream(inputString.getBytes("UTF-8"))

7
Хороша ReaderInputStreamреалізація зажадає менше пам'яті - не повинно бути необхідності зберігати всі байти в масиві одночасно.
Piotr Findeisen

3
Мені подобається це рішення, оскільки воно працює, коли вам потрібно модульний тестовий код, який приймає введення на (наприклад, стандартному введенні).
Kedar Mhaswade

43

Ну, Reader має справу з символами, а InputStream - з байтами. Кодування визначає, як ви хочете представляти своїх символів як байти, тому ви не можете насправді ігнорувати проблему. Що стосується уникнення проблем, то моя думка така: виберіть одну кодировку (наприклад, "UTF-8") і дотримуйтесь її.

Щодо того, як насправді це зробити, як вже зазначалося, " очевидними назвами цих класів є ReaderInputStream і WriterOutputStream . " Дивно, " вони не включені в бібліотеку Java ", хоча "протилежні" класи, InputStreamReader і OutputStreamWriter є включено.

Отже, багато людей придумали власні реалізації, включаючи Apache Commons IO . Залежно від питань ліцензування, ви, ймовірно, зможете включити бібліотеку commons-io до свого проекту або навіть скопіювати частину вихідного коду (який можна завантажити тут ).

Як бачите, в документації обох класів зазначено, що "всі кодування наборів символів, що підтримуються JRE, обробляються правильно".

Примітка. У коментарі до однієї з інших відповідей тут згадується про цю помилку . Але це впливає на клас Apache Ant ReaderInputStream ( тут ), а не на клас Apache Commons IO ReaderInputStream.


19

Також зауважте, що якщо ви починаєте з рядка, ви можете пропустити створення StringReader і створити InputStream за один крок, використовуючи org.apache.commons.io.IOUtils від Commons IO приблизно так:

InputStream myInputStream = IOUtils.toInputStream(reportContents, "UTF-8");

Звичайно, вам все одно потрібно подумати про кодування тексту, але принаймні перетворення відбувається в один крок.


4
Цей метод робить в основному new ByteArrayInputStream(report.toString().getBytes("utf-8")), що передбачає виділення двох додаткових копій звіту в пам’яті. Якщо звіт великий, це погано. Дивіться мою відповідь.
Олів,

8

Використання:

new CharSequenceInputStream(html, StandardCharsets.UTF_8);

Цей спосіб не вимагає попереднього перетворення в Stringта потім у byte[], що виділяє набагато більше пам'яті купи, на випадок, якщо звіт великий. Він перетворюється в байти на льоту, коли потік читається, прямо з StringBuffer.

Він використовує CharSequenceInputStream від проекту Apache Commons IO.



5

Очевидними назвами цих класів є ReaderInputStream та WriterOutputStream. На жаль, вони не входять до бібліотеки Java. Однак Google - ваш друг.

Я не впевнений, що він обійде всі проблеми кодування тексту, які є кошмарними.

Є RFE, але він закритий, не виправляє.


1
bugs.openjdk.java.net/browse/JDK-4103785 містить коментар "у нас є загальнодоступний API для кодування набору символів ... немає вагомих причин для додавання цих класів" - так як це зробити в Java 7, без додаткових бібліотеки, дванадцять років попереду?
Piotr Findeisen

5

Ви не можете уникнути проблем із кодуванням тексту, але Apache commons-io це робить

Зверніть увагу, що це бібліотеки, про які йдеться у відповіді Петра koders.com, просто посилання на бібліотеку замість вихідного коду.


4

Ви намагаєтесь записати вміст a Readerв an OutputStream? Якщо це так, вам буде легше обернути символ OutputStreamin OutputStreamWriterі записати chars від Readerдо до Writer, замість того , щоб намагатися перетворити зчитувач на 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

1

Попередження при використанні WriterOutputStream - воно не завжди обробляє запис двійкових даних у файл належним чином / те саме, що і звичайний вихідний потік. З цим у мене виникла проблема, через яку мені потрібно було трохи відстежити.

Якщо ви можете, я рекомендую використовувати вихідний потік як вашу базу, а якщо вам потрібно написати рядки, використовуйте обгортку OUtputStreamWriter навколо потоку, щоб зробити це. Перетворювати текст у байти набагато надійніше, ніж навпаки, імовірно, чому WriterOutputStream не є частиною стандартної бібліотеки Java



-1

Для читання рядка в потоці, використовуючи саме те, що постачає Java.

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

6
ReaderInputStream знаходиться в Apache Commons IO.
Вілл Бісон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.