2013-10-19 72 views
6

标题说明了一切。有没有什么办法可以从StringBuilder转换为byte []而不在中间使用String?Java:StringBuffer to byte [] without toString

问题是,我正在管理真正的大字符串(数百万字符),然后我有一个循环在最后添加一个字符并获得字节[]。将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

对于初学者,您应该使用StringBuilder,因为StringBuffer具有通常不必要的同步开销。

不幸的是,有没有办法直接去byte S,但你可以char的拷贝到一个数组或迭代从0length()和读取每个charAt()

+0

+1 StringBuffer的Javadoc说你应该使用StringBuilder将近十年。 –

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是不是我们都习惯了,但嘿,还有Clojure的保存其中提到的Java流利的日子:

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在CharBuffer中,因为StringBuilder的实现CharSequence中:

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); 

编辑:杜阿尔特正确地指出,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或创建一个byte []。相反,您可以逐步写入将首先获取数据的数据流。如果你不能这样做,你可以将StringBuilder中的数据复制到Writer中,但是首先不要创建StringBuilder要快得多。

+0

我们将如何逐步写入流?我有一个函数,采用字节[] – CyberMew

+0

您需要作为函数,您可以调用您迄今读过的字节[],例如https://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html#write(byte[],%20int,%20int)此函数允许您使用相同的byte []每个因此无论处理数据的大小如何都会使内存消耗和垃圾数量保持不变。 –

2

如果你愿意更换StringBuilder别的东西,另一种可能性是由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()); 

一如往常,您的里程可能会有所不同。