大型のByteBufferのためのBufferedReaderの?
-
20-08-2019 - |
質問
最初の文字列にそれを回すことなく、BufferedReaderのでのByteBufferを読み込む方法はありますか?私はそれをディスクに書き込まないようにしたいテキストの行として、およびパフォーマンス上の理由から、かなり大規模のByteBufferを読みたいです。結果の文字列が大きすぎるために動作しないのByteBufferに対してtoStringを呼び出す(:Javaヒープスペース、それでjava.lang.OutOfMemoryErrorをスローします)。私は、適切なリーダーでのByteBufferをラップするAPIで何かがあるだろうと思っているだろうが、私は、適切な何かを見つけるように見えることはできません。
ここでは省略コードサンプルのインクルードは)私がやっているものを示しています:
// 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
}
}
解決
それは明らかではありません。あなたがInputStream
を持って、あなたはそれのためにラインを読みたい場合は、なぜあなたはちょうどInputStreamReader
に包まれBufferedReader
を使用していませんか? NIOが巻き込までの利点は何でしょうか。
toString()
あなたはそれのためのスペースを持っていた場合でも、私には悪いアイデアのように聞こえるにByteArrayOutputStream
呼び出す:優れたバイト配列として取得し、ByteArrayInputStream
でそれをラップしてからする<=> 、あなたは本当に<=>を持っている必要があります。あなたがをした場合、本当にが<=>呼びたい、少なくとも使用する文字エンコーディングの名前をとるオーバーロードを使用する - それ以外の場合は、おそらくあなたが望むものではありませんこれは、システムのデフォルトを使用しますます。
編集:わかりましたので、あなたが本当にNIOを使用します。あなたはその中のデータをBAOSになってしまいますので、あなたはまだ、最終的に<=>に書いています。あなたがそのデータのコピーを作成することを回避したい場合は、このような場合のために、<=>から派生する必要があります:
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);
}
}
次に、あなたは、<=>でそれをラップし、入力ストリームを作成<=>にそれをラップし、あなたが離れていることができます。
他のヒント
あなたはNIOを使用することができますが、ここでは実際の必要はありません。ジョンスキートが示唆したように:
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;
}
}
そして、あなたはこのようにそれを使用することができます:
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);