Получить OutputStream в строку

580

Каков наилучший способ передать вывод из java.io.OutputStream в строку в Java?

Скажем, у меня есть метод:

  writeToStream(Object o, OutputStream out)

Который записывает определенные данные от объекта в данный поток. Тем не менее, я хочу получить этот вывод в строку как можно проще.

Я рассматриваю возможность написания такого класса (непроверенного):

class StringOutputStream extends OutputStream {

  StringBuilder mBuf;

  public void write(int byte) throws IOException {
    mBuf.append((char) byte);
  }

  public String getString() {
    return mBuf.toString();
  }
}

Но есть ли лучший способ? Я только хочу запустить тест!

Адриан Муат
источник
6
У вас есть только байты ASCII? Вам не нужна кодовая страница?
Horcrux7
В этом случае да. Однако, хороший момент - я не думал об этом.
Адриан Муат

Ответы:

607

Я бы использовал ByteArrayOutputStream. А на финише вы можете позвонить:

new String( baos.toByteArray(), codepage );

или лучше:

baos.toString( codepage );

Для Stringконструктора это codepageможет быть Stringили экземпляр java.nio.charset.Charset . Возможное значение: java.nio.charset.StandardCharsets.UTF_8 .

Метод toString()принимает только a Stringв качестве codepageпараметра (стенд Java 8).

Horcrux7
источник
8
ByteArrayOutputStream не имеет метода toArray (); это действительно toByteArray (), хотя. Вы можете исправить ответ? Кроме того, почему бы не использовать baos.toString (String charsetName), который был бы немного проще.
Джоник
35
Bytearray - это просто двоичные данные. Так как текст (Unicode) может быть закодирован в двоичном виде различными способами, ByteArrayOutputStream должен знать, какая кодировка использовалась для кодирования байтов, поэтому он может использовать ту же кодировку для повторного декодирования байтов в строку. Простое использование toString без аргумента нецелесообразно, поскольку вы просто игнорируете проблему, а не решаете ее; Java будет использовать кодировку платформы, которая может быть правильной ... или нет. Это случайно в принципе. Вам необходимо выяснить, какая кодировка использовалась для записи текста в байты и передать эту кодировку в toString.
Стейн де Витт
10
Просто пояснение к кодовой странице, на которую есть ссылка: в Java вы можете использовать Charset.defaultCharset () или Charset.forName («конкретная кодировка»); То, что работало для меня, было: новая строка (baos.toByteArray (), Charset.defaultCharset ());
Уоллес Браун
7
Использование @WallaceBrown ничуть defaultCharsetне лучше, чем полное игнорирование кодировки - вам нужно выяснить, что это такое, прежде чем использоватьtoString
artbristol
4
StandardCharsets.UTF_8это Charset, а не String. Причем параметр называется charsetName, а не codepage.
OrangeDog
46

Мне нравится библиотека Apache Commons IO. Взгляните на его версию ByteArrayOutputStream , которая также имеет toString(String enc)метод toByteArray(). Использование существующих и надежных компонентов, таких как проект Commons, позволяет уменьшить размер вашего кода и облегчить его расширение и перепрофилирование.

Джо Ливерседж
источник
10
Сохраните себе год своей жизни и прочитайте все распространенные API, чтобы при возникновении проблемы вы могли использовать полностью протестированное решение, принадлежащее сообществу.
Боб Херрманн
15
Хм, я заядлый пользователь Apache Commons, но в этом случае я не понимаю, почему вы должны использовать ByteArrayOutputStream Commons IO вместо собственного java.io.ByteArrayOutputStream JDK. Последний также предоставляет методы toString (String charsetName) и toByteArray (). Хотите разработать?
Джоник
1
Да, так как исходный контекст был лучшим способом для потоковой передачи и извлечения контента, я включил пример ввода-вывода Commons, так как он включал метод write (InputStream) для тогда еще неопределенного / сомнительного механизма для заполнения OutputStream. Я бы тоже пошел с JDK.
Джо Ливерседж
23

Это сработало

OutputStream output = new OutputStream() {
    private StringBuilder string = new StringBuilder();

    @Override
    public void write(int b) throws IOException {
        this.string.append((char) b );
    }

    //Netbeans IDE automatically overrides this toString()
    public String toString() {
        return this.string.toString();
    }
};

вызов метода = >> marshaller.marshal( (Object) toWrite , (OutputStream) output);

затем напечатать строку или получить ее, просто ссылаясь на сам поток «output». Например, вывести строку в console = >> System.out.println(output);

К вашему сведению: мой метод вызова marshaller.marshal(Object,Outputstream)для работы с XML. Это не имеет отношения к этой теме.

Это очень расточительно для производственного использования, существует слишком много конверсии, и она немного неэффективна. Это было просто закодировано, чтобы доказать вам, что вполне возможно создать собственный OuputStream и вывести строку. Но просто идите Horcrux7, и все хорошо, всего лишь два вызова метода.

И мир живет в другой день ....

РС
источник
9
Просто приведение байта к char будет работать только на ascii. Используйте ByteArrayOutputStream как Horcrux7
Дейв Рэй
2
Договорились с Дейвом Рэем. Вы не можете предполагать, что ваш байт является символом ASCII. Вам нужно интерпретировать байты, используя кодировку. Используйте byteArrayOutputStream.toString ("UTF-8") или новую строку (byteArrayOutputStream.toByteArray (), "UTF-8").
Мартин Доу
16

Вот что я в итоге сделал:

Obj.writeToStream(toWrite, os);
try {
    String out = new String(os.toByteArray(), "UTF-8");
    assertTrue(out.contains("testString"));
} catch (UnsupportedEncondingException e) {
    fail("Caught exception: " + e.getMessage());
}

Где ОС это ByteArrayOutputStream.

Адриан Муат
источник
2
@JavaJigs Я пояснил это в нижней части моего ответа почти 5 лет назад :)
Адриан Муат
19
Рассмотрите возможность замены "UTF-8"на StandardCharsets.UTF_8.
james.garriss
0
baos.toString(StandardCharsets.UTF_8);

Преобразует содержимое буфера в строку путем декодирования байтов с использованием именованного набора символов.

Java 14 - https://docs.oracle.com/

jschnasse
источник