将 outputStream 转换为字节数组

converting outputStream to byte array

如何获取 outputStream 的字节,或者如何将 outputStream 转换为字节数组?

@Obicere 评论示例:

ByteArrayOutputStream btOs = new ByteArrayOutputStream();
btOs.write("test bytes".getBytes());    
String restoredString = new String(btOs.toByteArray());
System.out.println(restoredString);

从理论的角度来看(即,不管它作为一个用例在实践中是否有意义),这是一个有趣的问题,本质上需要实现像

这样的方法
public abstract byte[] convert(OutputStream out);

Java OutputStream class,顾名思义,只支持 I/O 的覆盖 write() 方法,并且 write() 方法要么整数(代表 1 个字节)或 byte 数组,其内容发送到输出(例如文件)。

例如,以下代码将 data 数组中已经存在的字节保存到 output.txt 文件中:

byte[] data = ... // Get some data
OutputStream fos = new FileOutputStream("path/to/output.txt");
fos.write(data);

为了获取给定 OutputStream 将输出的所有数据并将其放入 byte 数组(即放入 byte[] 对象),class,从中实例化了相应的 OutputStream 对象,应该继续存储通过其 write() 方法处理的所有字节,并提供一个特殊的方法,例如 toByteArray(),这将 return 全部,在调用时。

这正是 ByteArrayOutputStream class 所做的,使 convert() 方法变得微不足道(并且不必要):

public byte[] convert(ByteArrayOutputStream out) {
  return out.toByteArray();
}

对于任何其他类型的 OutputStream,本质上不支持对 byte[] 对象的类似转换,在 OutputStream 被耗尽之前无法进行转换,即在完成对其 write() 方法的所需调用之前。

如果可以做出这样的假设(写入已经完成),并且如果可以替换原始 OutputStream 对象,那么一种选择是将其包装在委托中 class 本质上 "grab" 将通过其 write() 方法提供的字节。例如:

public class DrainableOutputStream extends FilterOutputStream {
  private final ByteArrayOutputStream buffer;
  public DrainableOutputStream(OutputStream out) {
    super(out);
    this.buffer = new ByteArrayOutputStream();
  }
  @Override
  public void write(byte b[]) throws IOException {
    this.buffer.write(b);
    super.write(b);
  }
  @Override
  public void write(byte b[], int off, int len) throws IOException {
    this.buffer.write(b, off, len);
    super.write(b, off, len);
  }
  @Override
  public void write(int b) throws IOException {
    this.buffer.write(b);    
    super.write(b);
  }
  public byte[] toByteArray() {
    return this.buffer.toByteArray();
  }
}

调用内部 "buffer" (ByteArrayOutputStream) 的 write() 方法先于调用原始流(反过来,可以通过 super,甚至通过 this.out,因为 FilterOutputStream 的相应参数是 protected)。这确保字节将被缓冲,即使在写入原始流时出现异常也是如此。

为了减少开销,可以省略上面 class 中对 super 的调用 - 例如,如果只需要对 byte 数组的 "conversion" .即使 ByteArrayOutputStreamOutputStream classes 也可以用作父 classes,需要更多的工作和一些假设(例如,关于 reset() 方法).

在任何情况下,都必须有足够的内存才能进行排空​​并使 toByteArray() 方法起作用。