BufferedReader用于大型ByteBuffer?

Rob*_*Rob 3 java nio bytebuffer bufferedreader

有没有办法用BufferedReader读取ByteBuffer而不必先将它变成String?我想通过相当大的ByteBuffer读取文本行,出于性能原因,我想避免将其写入磁盘.在ByteBuffer上调用toString不起作用,因为生成的String太大(它会抛出java.lang.OutOfMemoryError:Java堆空间).我原以为API中会有一些东西将ByteBuffer包装在合适的阅读器中,但我似乎找不到合适的东西.

这是一个缩写代码示例,说明了我在做什么):

// input stream is from Process getInputStream()
public String read(InputStream istream)
{
  ReadableByteChannel source = Channels.newChannel(istream);
  ByteArrayOutputStream ostream = new ByteArrayOutputStream(bufferSize);
  WritableByteChannel destination = Channels.newChannel(ostream);
  ByteBuffer buffer = ByteBuffer.allocateDirect(writeBufferSize);

  while (source.read(buffer) != -1)
  {
    buffer.flip();
    while (buffer.hasRemaining())
    {
      destination.write(buffer);
    }
    buffer.clear();
  }

  // this data can be up to 150 MB.. won't fit in a String.
  result = ostream.toString();
  source.close();
  destination.close();
  return result;
}

// after the process is run, we call this method with the String
public void readLines(String text)
{
  BufferedReader reader = new BufferedReader(new StringReader(text));
  String line;

  while ((line = reader.readLine()) != null)
  {
    // do stuff with line
  }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 5

目前尚不清楚为什么要使用字节缓冲区来开始.如果你有一个InputStream并且你想读它的线,你为什么不用一个InputStreamReader包装BufferedReader?让NIO参与的好处是什么?

调用toString()ByteArrayOutputStream像一个坏主意的声音对我来说,即使你必须为它的空间:更好地得到它作为一个字节数组,敷在ByteArrayInputStream后的InputStreamReader,如果你真的必须有一个ByteArrayOutputStream.如果你真的想调用toString(),至少使用带有字符编码名称的重载来使用 - 否则它将使用系统默认值,这可能不是你想要的.

编辑:好的,所以你真的想要使用NIO.你还在写ByteArrayOutputStream最终的,所以你最终会得到一个带有数据的BAOS.如果你想避免复制那些数据,你需要派生出来ByteArrayOutputStream,例如:

public class ReadableByteArrayOutputStream extends ByteArrayOutputStream
{
    /**
     * Converts the data in the current stream into a ByteArrayInputStream.
     * The resulting stream wraps the existing byte array directly;
     * further writes to this output stream will result in unpredictable
     * behavior.
     */
    public InputStream toInputStream()
    {
        return new ByteArrayInputStream(array, 0, count);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以创建输入流,将其包装成一个InputStreamReader包装BufferedReader,然后你就可以了.

  • 所以用ByteArrayOutputStream把它放到一个字节数组中.一旦你把它作为一个字节数组,你就没事了.无论如何,这实际上是NIO要做的事情,对于BAOS而言,它更加直截了当.如果它将是巨大的,您*可能*想要派生自己的ByteArrayOutputStream,它允许您直接访问字节数组,因此您不必担心使用toByteArray()创建副本.很遗憾ByteArrayOutputStream没有"toByteArrayInputStream"让你直接从它读取... (2认同)