将OutputStream转换为String

669

如何在Java中将java.io.OutputStream的输出导入到一个字符串中是最好的方法?

假设我有以下方法:

  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个回答

695

我会使用ByteArrayOutputStream。并在结束时调用:

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

更好的方式:

baos.toString( codepage );
对于String构造函数,codepage可以是一个Stringjava.nio.charset.Charset的实例。一个可能的值是java.nio.charset.StandardCharsets.UTF_8toString()方法只接受一个String作为codepage参数(标准的Java 8版本)。

9
ByteArrayOutputStream没有toArray()方法,但它确实有toByteArray()方法。你能修正一下答案吗?另外,为什么不使用baos.toString(String charsetName)呢?这样会更简单一些。 - Jonik
40
一个bytearray只是二进制数据。由于(Unicode)文本可以用许多不同的方式编码为二进制,因此ByteArrayOutputStream需要知道用于编码字节的编码方式,以便再次将字节解码为字符串时使用相同的编码方式。仅使用没有参数的toString并不明智,因为这样您只是忽略了问题而不是解决它。Java将使用平台编码,这可能是正确的...也可能不是。基本上是随机的。您需要找出用于将文本写入字节的编码方式,并将该编码方式传递给toString。 - Stijn de Witt
12
在这里需要澄清的是编码页面:在Java中,您可以使用Charset.defaultCharset()或Charset.forName("specific charset")。对我有效的是:new String(baos.toByteArray(), Charset.defaultCharset()); - Wallace Brown
7
@WallaceBrown 使用defaultCharset并不比完全忽略字符集更好 - 在使用toString之前,你需要先找出它是什么。 - artbristol
5
StandardCharsets.UTF_8 是一个 Charset(字符集),而不是一个 String(字符串)。此外,该参数被称为 charsetName(字符集名称),而不是 codepage(代码页)。 - OrangeDog
显示剩余8条评论

54

我喜欢Apache Commons IO库。看一下它的版本ByteArrayOutputStream,它有一个toString(String enc)方法和一个toByteArray()方法。使用像Commons项目这样的现有和值得信赖的组件可以使您的代码更小、更易于扩展和重新使用。


12
节省一年的时间,阅读所有常用的API,这样当你遇到问题时,就可以释放一个经过充分测试和社区拥有的解决方案。 - Bob Herrmann
17
我是一名狂热的Apache Commons用户,但在这种情况下,我不明白为什么您应该使用Commons IO的ByteArrayOutputStream而不是JDK自己的java.io.ByteArrayOutputStream。后者也提供了toString(String charsetName)和toByteArray()方法。能详细解释一下吗? - Jonik
1
是的,因为原始上下文是一种更好的流和提取内容的方式,所以我包括了Commons IO示例,因为它包括一个“write(InputStream)”方法,用于填充OutputStream的未定义/有问题的机制。我也会选择JDK。 - Joe Liversedge

29

这个很好地运作了

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”流本身。例如,将字符串打印到控制台 =>> System.out.println(output);

FYI:我的方法调用marshaller.marshal(Object,Outputstream)用于处理XML。它与此主题无关。

这对于生产使用来说非常浪费,有太多的转换并且有点松散。这只是编码的证明,表明完全可以创建自定义OuputStream并输出字符串。但是,只需按照Horcrux7的方式进行操作,仅需两个方法调用即可轻松解决问题。

世界因此而继续运转....


12
仅将字节强制转换为字符只适用于 ASCII 编码。像 Horcrux7 一样使用 ByteArrayOutputStream。 - Dave Ray
2
同意Dave Ray的观点。你不能假设你的字节是ASCII字符。你需要使用编码来解释这些字节。使用byteArrayOutputStream.toString("UTF-8")或new String(byteArrayOutputStream.toByteArray(), "UTF-8")。 - Martin Dow

19

这是我最终采取的做法:

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是一个ByteArrayOutputStream


2
@JavaJigs,我在将近5年前的答案底部澄清了这一点 :) - Adrian Mouat
21
考虑将"UTF-8"替换为StandardCharsets.UTF_8 - james.garriss

9

-2

这是我所做的(不要在生产环境中使用,这并不好!但它可以使修复多个错误更容易。)

  • 创建一个保存异常的列表。

  • 创建一个记录异常的日志器。

  • 使用以下代码:

    private static void exceptionChecker() throws Exception { if(exceptionList.isEmpty()) return; //没有异常,太好了,什么都不用做 :)

      //为多线程创建锁
      synchronized (System.err){
          //创建新的错误流
          ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
          PrintStream errorOut = new PrintStream(byteArrayOutputStream);
    
          //保存标准错误输出
          PrintStream standardErrOut = System.err;
    
          try{
              //设置新的错误流
              System.setErr(errorOut);
    
              exceptionList.forEach(exception -> {
                  exception.printStackTrace();
                  System.err.println("<---------->");
              });
    
    
          } finally {
              //将所有内容恢复到正常状态
              System.setErr(standardErrOut);
    
              //记录所有异常
              exceptionLogger.warning(byteArrayOutputStream.toString());
    
              //抛出最终的通用异常
              throw new Exception();
          }
      }}
    

这并不是很好,因为你在 finally 块中抛出了一个错误,并且它会锁定错误流,但它适用于开发目的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接