Java 大型ByteBuffer的BufferedReader?

Java 大型ByteBuffer的BufferedReader?,java,nio,bufferedreader,bytebuffer,Java,Nio,Bufferedreader,Bytebuffer,有没有一种方法可以使用BufferedReader读取ByteBuffer,而不必先将其转换为字符串?我希望将相当大的字节缓冲区作为文本行进行读取,出于性能原因,我希望避免将其写入磁盘。在ByteBuffer上调用toString不起作用,因为生成的字符串太大(它抛出java.lang.OutOfMemoryError:java堆空间)。我本以为API中会有一些东西可以将ByteBuffer封装在合适的阅读器中,但我似乎找不到任何合适的东西 下面是一个简短的代码示例,说明了我正在做的事情): 现

有没有一种方法可以使用BufferedReader读取ByteBuffer,而不必先将其转换为字符串?我希望将相当大的字节缓冲区作为文本行进行读取,出于性能原因,我希望避免将其写入磁盘。在ByteBuffer上调用toString不起作用,因为生成的字符串太大(它抛出java.lang.OutOfMemoryError:java堆空间)。我本以为API中会有一些东西可以将ByteBuffer封装在合适的阅读器中,但我似乎找不到任何合适的东西

下面是一个简短的代码示例,说明了我正在做的事情):


现在还不清楚为什么要使用字节缓冲区。如果你有一个
InputStream
并且你想为它读行,为什么不使用一个
InputStreamReader
包装在
BufferedReader
中呢?让NIO参与进来有什么好处

ByteArrayOutputStream
上调用
toString()
对我来说听起来是个坏主意,即使你有足够的空间:如果你真的需要一个
ByteArrayOutputStream
,最好将它作为字节数组,并将其包装在
ByteArrayInputStream
InputStreamReader
中。如果你真的想调用
toString()
,至少要使用重载,该重载取要使用的字符编码的名称-否则它将使用系统默认值,这可能不是你想要的

编辑:好的,所以你真的想使用NIO。最终,您仍在通过tearrayoutputstream向
写入数据,因此最终将得到一个包含数据的BAO。如果要避免复制该数据,则需要从
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);
    }
}
    String text = "this is text";   // It can be Unicode text
    ByteBuffer buffer = ByteBuffer.wrap(text.getBytes("UTF-8"));

    InputStream is = new ByteBufferBackedInputStream(buffer);
    InputStreamReader r = new InputStreamReader(is, "UTF-8");
    BufferedReader br = new BufferedReader(r);

然后您可以创建输入流,将其包装在
InputStreamReader
中,将其包装在
BufferedReader
中,然后您就可以离开了。

您可以使用NIO,但这里没有真正的需要。正如Jon Skeet所建议的:

public byte[] read(InputStream istream)
{
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  byte[] buffer = new byte[1024]; // Experiment with this value
  int bytesRead;

  while ((bytesRead = istream.read(buffer)) != -1)
  {
    baos.write(buffer, 0, bytesRead);
  }

  return baos.toByteArray();
}


// after the process is run, we call this method with the String
public void readLines(byte[] data)
{
  BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(data)));
  String line;

  while ((line = reader.readLine()) != null)
  {
    // do stuff with line
  }
}
这是一个示例:

public class ByteBufferBackedInputStream extends InputStream {

    ByteBuffer buf;

    public ByteBufferBackedInputStream(ByteBuffer buf) {
        this.buf = buf;
    }

    public synchronized int read() throws IOException {
        if (!buf.hasRemaining()) {
            return -1;
        }
        return buf.get() & 0xFF;
    }

    @Override
    public int available() throws IOException {
        return buf.remaining();
    }

    public synchronized int read(byte[] bytes, int off, int len) throws IOException {
        if (!buf.hasRemaining()) {
            return -1;
        }

        len = Math.min(len, buf.remaining());
        buf.get(bytes, off, len);
        return len;
    }
}
您可以这样使用它:

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);
    }
}
    String text = "this is text";   // It can be Unicode text
    ByteBuffer buffer = ByteBuffer.wrap(text.getBytes("UTF-8"));

    InputStream is = new ByteBufferBackedInputStream(buffer);
    InputStreamReader r = new InputStreamReader(is, "UTF-8");
    BufferedReader br = new BufferedReader(r);

好问题-我会同意,如果我有选择的话,我会这么做。在这种情况下,我不能这样做的原因是,在进程完成之前,我不能对进程的输出(即InputStream)做任何事情,因此我需要将其放入缓冲区以便稍后读取。因此,请将其放入带有ByteArrayOutputStream的字节数组中。一旦你把它作为一个字节数组,你就没事了。这正是NIO将要做的事情,对于BAO来说,这更简单。如果它将是巨大的,您可能希望派生您自己的ByteArrayOutputStream,它允许您直接访问字节数组,因此您不必担心使用toByteArray()创建副本。很遗憾ByteArrayOutputStream没有一个“toByteArrayInputStream”让你直接从中阅读……至于我为什么使用NIO:部分原因是我是受虐狂,决心一劳永逸地解决NIO(如果事实上这是人的可能的话),部分原因是我希望尽可能快地读取输入流,而NIO在这方面似乎更快。好吧,如果你真的,真的想使用NIO编辑答案。虽然这不是我接受的答案(因为我想尝试使用NIO),但像这样使用标准IO比NIO方法更快。尽管如此,尝试NIO还是一次很好的学习经历。