Obter um OutputStream em uma String

580

Qual é a melhor maneira de canalizar a saída de um java.io.OutputStream para uma String em Java?

Digamos que eu tenho o método:

  writeToStream(Object o, OutputStream out)

Que grava certos dados do objeto no fluxo especificado. No entanto, quero obter essa saída em uma String o mais facilmente possível.

Estou pensando em escrever uma classe como esta (não testada):

class StringOutputStream extends OutputStream {

  StringBuilder mBuf;

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

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

Mas existe uma maneira melhor? Eu só quero fazer um teste!

Adrian Mouat
fonte
6
Você tem apenas bytes ASCII? Você não precisa de uma página de código?
Horcrux7 19/10/08
Nesse caso sim. No entanto, bom ponto - eu não tinha pensado nisso.
Adrian Mouat

Respostas:

607

Eu usaria um ByteArrayOutputStream. E, no final, você pode ligar para:

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

ou melhor:

baos.toString( codepage );

Para o Stringconstrutor, codepagepode ser uma Stringou uma instância de java.nio.charset.Charset . Um valor possível é java.nio.charset.StandardCharsets.UTF_8 .

O método toString()aceita apenas a Stringcomo codepageparâmetro (suporte Java 8).

Horcrux7
fonte
8
ByteArrayOutputStream não possui o método toArray (); ele tem toByteArray (). Você pode consertar a resposta? Além disso, por que não usar baos.toString (String charsetName), que seria um pouco mais simples.
Jonik
35
Um bytearray é apenas dados binários. Como o texto (unicode) pode ser codificado em binário de várias maneiras diferentes, o ByteArrayOutputStream precisa saber qual codificação foi usada para codificar os bytes, para que possa usar a mesma codificação para decodificar os bytes em uma string novamente. Simplesmente usar toString sem argumento não é aconselhável, pois você simplesmente ignora o problema em vez de resolvê-lo; Java usará a codificação da plataforma que pode estar correta ... ou não. É aleatório basicamente. Você precisa descobrir qual codificação foi usada para gravar o texto em bytes e passar essa codificação para toString.
Stijn de Witt
10
Apenas um esclarecimento sobre a página de código mencionada aqui: em Java, você pode usar Charset.defaultCharset () ou Charset.forName ("charset específico"); O que funcionou para mim foi: new String (baos.toByteArray (), Charset.defaultCharset ());
Wallace Brown
7
@WallaceBrown usando defaultCharsetvocê precisa descobrir o que é antes de usar - não melhor do que ignorar o charset completo étoString
artbristol
4
StandardCharsets.UTF_8é um Charset, não um String. Além disso, o parâmetro é chamado charsetName, não codepage.
1811 OrangeDog
46

Gosto da biblioteca Apache Commons IO. Dê uma olhada em sua versão do ByteArrayOutputStream , que também possui um toString(String enc)método toByteArray(). O uso de componentes existentes e confiáveis, como o projeto Commons, permite que seu código seja menor e mais fácil de estender e redefinir.

Joe Liversedge
fonte
10
Salve-se um ano de sua vida e leia todas as APIs comuns para encontrar um problema, pois você pode lançar uma solução totalmente testada e de propriedade da comunidade.
Bob Herrmann
15
Hmm, sou um usuário ávido do Apache Commons, mas neste caso não consigo entender por que você deve usar o ByteArrayOutputStream do Commons IO em vez do java.io.ByteArrayOutputStream do JDK. O último também fornece os métodos toString (String charsetName) e toByteArray (). Cuidado ao elaborar?
9119 Jonik
1
Sim, como o contexto original era uma maneira melhor de transmitir e extrair conteúdo, incluí o exemplo do Commons IO, pois incluía um método 'write (InputStream)' para um mecanismo então indefinido / questionável para preencher o OutputStream. Eu iria com o JDK também.
Joe Liversedge
23

Isso funcionou bem

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();
    }
};

chamada de método = >> marshaller.marshal( (Object) toWrite , (OutputStream) output);

em seguida, para imprimir a string ou obtê-la, faça referência ao próprio fluxo "output". Como exemplo, para imprimir a string no console = >> System.out.println(output);

FYI: minha chamada de método marshaller.marshal(Object,Outputstream)é para trabalhar com XML. É irrelevante para este tópico.

Isso é um grande desperdício para uso produtivo, há uma conversão demais e é um pouco solto. Isso foi codificado apenas para provar a você que é totalmente possível criar um OuputStream personalizado e gerar uma string. Mas basta seguir o caminho do Horcrux7 e tudo fica bem com apenas duas chamadas de método.

E o mundo vive em outro dia ....

em
fonte
9
Apenas converter um byte para char só funcionará em ascii. Use ByteArrayOutputStream como Horcrux7
Dave Ray
2
Concordo com Dave Ray. Você não pode assumir que seu byte é um caractere ASCII. Você precisa interpretar os bytes usando uma codificação. Use byteArrayOutputStream.toString ("UTF-8") ou nova String (byteArrayOutputStream.toByteArray (), "UTF-8").
Martin Dow
16

Aqui está o que eu acabei fazendo:

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());
}

Onde os é a ByteArrayOutputStream.

Adrian Mouat
fonte
2
@JavaJigs Eu esclareci isso no fundo da minha resposta quase 5 anos atrás :)
Adrian Mouat
19
Considere substituir "UTF-8"por StandardCharsets.UTF_8.
Json.garriss 18/12/2015
0
baos.toString(StandardCharsets.UTF_8);

Converte o conteúdo do buffer em uma seqüência de caracteres decodificando os bytes usando o charset nomeado.

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

jschnasse
fonte