Отримайте OutputStream у рядок


580

Який найкращий спосіб передавати вихід з java.io.OutputStream на String на Java?

Скажіть, у мене є метод:

  writeToStream(Object o, OutputStream out)

Який записує певні дані з об'єкта в даний потік. Однак я хочу, щоб цей вихід був в String якомога легше.

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

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()приймає лише параметр Stringa codepage(параметр Java 8).


8
ByteArrayOutputStream не має методу toArray (); він, однак, маєByteArray (). Чи можете ви виправити відповідь? Крім того, чому б не використовувати baos.toString (String charsetName), що було б трохи простіше.
Jonik

35
Байт-масив - це лише двійкові дані. Оскільки (unicode) текст може бути кодований бінарним різними способами, ByteArrayOutputStream повинен знати, яке кодування використовувалося для кодування байтів, тому він може використовувати те саме кодування, щоб знову розшифрувати байти до рядка. Просто використовувати toString без аргументу нерозумно, оскільки ви просто ігноруєте проблему, а не вирішувати її; Java використовуватиме кодування платформи, яка може бути правильною ... чи ні. Це в основному випадково. Потрібно дізнатися, яке кодування використовувалося для написання тексту в байти і передавати це кодування в toString.
Штійн де Вітт

10
Просто уточнення щодо кодованої сторінки, на яку посилається тут: на Java ви можете використовувати Charset.defaultCharset () або Charset.forName ("специфічна діаграма"); Що для мене працювало: нова струна (baos.toByteArray (), Charset.defaultCharset ());
Уоллес Браун

7
@WallaceBrown використовувати defaultCharsetне краще, ніж взагалі ігнорувати шаблони - вам потрібно з’ясувати, що це перед тим, як використовуватиtoString
artbristol

4
StandardCharsets.UTF_8є a Charset, не a String. Причому параметр викликається charsetName, а не codepage.
OrangeDog

46

Мені подобається бібліотека AOche Commons IO. Погляньте на його версію ByteArrayOutputStream , яка також має toString(String enc)метод toByteArray(). Використання існуючих та надійних компонентів, таких як проект Commons, дозволяє вашому коду бути меншим та простішим для розширення та зміни.


10
Збережіть собі рік свого життя та прочитайте всі API-коди загального користування, тож, коли ви зіткнетеся з проблемою, ви зможете відкрити повністю перевірене рішення, яке належить громаді.
Боб Геррман

15
Хм, я завзятий користувач Apache Commons, але в цьому випадку я не розумію, чому ви повинні використовувати BytesArrayOutputStream Iomo Commons замість власного java.io.ByteArrayOutputStream JDK. Останній також забезпечує методи toString (String charsetName) та toByteArray (). Хочете допрацювати?
Jonik

1
Так, оскільки початковий контекст був кращим способом передавати та витягувати вміст, я включив приклад ІМ Commons, оскільки він включав метод 'написати (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);

потім надрукувати рядок або отримати просто посилання на "вихідний" потік Як приклад, щоб надрукувати рядок на консоль = >> System.out.println(output);

FYI: мій виклик методу 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());
}

Де os - a ByteArrayOutputStream.


2
@JavaJigs Я уточнив це внизу своєї відповіді майже 5 років тому :)
Адріан Муат

19
Розглянемо заміну "UTF-8"на StandardCharsets.UTF_8.
james.garriss

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