2013-10-19 25 views
6

タイトルはそれをすべて言います。途中でStringを使用せずにStringBuilderからbyte []に​​変換する方法はありますか?Java:StringBuffer to byte [] toStringなし

問題は、本当に大きな文字列(何百万もの文字)を管理していて、最後にcharを追加してバイト[]を取得するサイクルがあることです。 StringBufferをStringに変換するプロセスは、このサイクルをとても非常に遅くします。

これを行う方法はありますか?前もって感謝します!

+0

最も近いものは、 'char []'配列を得ることです。 StringBuffer#getChars(int、int、char []、int) –

+2

代わりに[CharBuffer](http://docs.oracle.com/javase/7/docs/api/java/nio/CharBuffer.html)を使用してみませんか?そして、 "charBuffer.array()"を実行しますか? – tolitius

+2

これらの大きな文字列をすべてメモリに保存する必要がある理由を明確にすることはできますか?ユーザーが待っているのですか?これは代わりにMapReduceまたはSparkジョブになる可能性がありますか?おそらくこの質問が建築デザインの匂いの症状であるかどうかは不思議です。 – Vidya

答えて

1

StringBufferには通常は不要な同期オーバーヘッドがあるため、まずはStringBuilderを使用してください。

は残念ながら、byte Sに直接移動する方法はありませんが、あなたは配列にchar Sをコピーしたり、0からlength()に反復処理し、各charAt()を読むことができます。

+0

+1そしてStringBufferのJavadocは、StringBuilderを10年近く使用するべきだと言っています。 –

0

「何百万もの文字」で何を達成しようとしていますか?これらのログは解析する必要がありますか?あなたはちょうどバイトとしてそれを読んでByteBufferに固執することができますか?次に、あなたが行うことができます。

buffer.array() 

byte[]

を取得するために、それはあなたがやっている何であるかに依存し、あなたもちょうどchar[]CharBufferを使用することができます。

CharBuffer cb = CharBuffer.allocate(4242); 
cb.put("Depends on what it is you need to do"); 
... 

次に、あなたがすることができますchar[]を次のように取得します。

cp.array() 

REPLを使うのはいつも良いことですが、それは楽しく、ポイントを証明します。 JavaのREPLは流暢でJavaを話すの日を保存することはClojureがあり、ちょっと我々が慣れているものではありません、しかし:

user=> (import java.nio.CharBuffer) 
java.nio.CharBuffer 

user=> (def cb (CharBuffer/allocate 4242)) 
#'user/cb 

user=> (-> (.put cb "There Be") (.array)) 
#<char[] [[email protected]> 

user=> (-> (.put cb " Dragons") (.array) (String.)) 
"There Be Dragons" 
11

すでに、あなたはCharBufferのクラスを使用しますが、新しいCharBufferのを割り当てることができます示唆しているとして、多くのあなたの問題を悪化させるだけです。 StringBuilderのはのCharSequenceを実装しているので

代わりに、あなたが直接、CharBufferの中であなたのStringBuilderをラップすることができます

Charset charset = StandardCharsets.UTF_8; 
CharsetEncoder encoder = charset.newEncoder(); 

// No allocation performed, just wraps the StringBuilder. 
CharBuffer buffer = CharBuffer.wrap(stringBuilder); 

ByteBuffer bytes = encoder.encode(buffer); 

EDIT:ドゥアルテが正しくCharsetEncoder.encode方法は、その裏配列よりも大きいバッファーを返すことが指摘実際のデータ意味、その容量はその限界よりも大きい。 ByteBuffer自体から読み取るか、正しいサイズであることが保証されているByteBufferからバイト配列を読み取る必要があります。

ByteBuffer byteBuffer = encoder.encode(buffer); 

byte[] array; 
int arrayLen = byteBuffer.limit(); 
if (arrayLen == byteBuffer.capacity()) { 
    array = byteBuffer.array(); 
} else { 
    // This will place two copies of the byte sequence in memory, 
    // until byteBuffer gets garbage-collected (which should happen 
    // pretty quickly once the reference to it is null'd). 

    array = new byte[arrayLen]; 
    byteBuffer.get(array); 
} 

byteBuffer = null; 
+0

正解の場合は+1も正しく、文字セットのエンコーディングを実装します。 –

+1

注意:ByteBuffer.array()はバッキング配列全体を返します。これには余分なバイトが含まれている可能性があります。 –

0

パフォーマンスをしたい場合、私はStringBuilderのを使用するか、バイト[]を作成しないでしょう。後者の場合は、何も簡単にいえ、メモリ内のバイトの2つのコピーを持つ回避はありません。代わりに、最初にデータを取得するストリームに徐々に書き込むことができます。できない場合は、StringBuilderからWriterにデータをコピーできますが、最初はStringBuilderを作成しないほうがはるかに高速です。

+0

ストリームに徐々に書き込む方法は?私はバイト[]を取る関数を持っています – CyberMew

+0

関数としてあなたはこれまでに読んだバイト[]で呼ぶことができます。 https://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html#write(byte[],%20int,%20int)この関数を使用すると、それぞれ同じバイト[]を使用できます処理されるデータのサイズにかかわらず、メモリ消費量とゴミを一定にします。 –

1

残念ながら、ByteBufferのarray()メソッドを扱う上記の答えはちょっとバグです...問題は、割り当てられたバイト[]が期待していたよりも大きくなる可能性があるということです。したがって、Javaで配列のサイズを変更することはできないため、削除するのが難しいNULLバイトが後になります。あなたが何か他のものとStringBuilderを置き換えるために喜んでいる場合 http://worldmodscode.wordpress.com/2012/12/14/the-java-bytebuffer-a-crash-course/

2

、さらに別の可能性はByteArrayOutputStreamに裏打ちされたWriter次のようになります:ここで

はこれをより詳細に説明する記事です

ByteArrayOutputStream bout = new ByteArrayOutputStream(); 
Writer writer = new OutputStreamWriter(bout); 
try { 
    writer.write("String A"); 
    writer.write("String B"); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
System.out.println(bout.toByteArray()); 

try { 
    writer.write("String C"); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
System.out.println(bout.toByteArray()); 

いつものように、あなたの走行距離は異なる場合があります。