标题说明了一切。有没有办法从StringBuilder转换为byte []而不在中间使用String?
问题是我管理的是真正的大字符串(数百万个字符),然后我有一个循环,最后添加一个字符并获得字节[]。将StringBuffer转换为String的过程使得这个循环非常非常慢。
有没有办法实现这个目标?提前谢谢!
答案 0 :(得分: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);
编辑: Duarte正确地指出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;
答案 1 :(得分:2)
如果您愿意将StringBuilder
替换为其他内容,则另一种可能性是由Writer
支持的ByteArrayOutputStream
:
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());
与往常一样,您的里程可能会有所不同。
答案 2 :(得分:1)
对于初学者,您可能应该使用StringBuilder
,因为StringBuffer
具有通常不必要的同步开销。
很遗憾,没有办法直接转到byte
,但您可以将char
复制到数组中或从0
迭代到length()
并阅读每个charAt()
。
答案 3 :(得分:1)
不幸的是,上面那些处理ByteBuffer的array()方法的答案有点儿麻烦......问题是分配的字节[]可能比你预期的要大。因此,将存在难以摆脱的尾随NULL字节,因为您无法在Java中“重新调整”数组大小。
这篇文章更详细地解释了这一点: http://worldmodscode.wordpress.com/2012/12/14/the-java-bytebuffer-a-crash-course/
答案 4 :(得分: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[] [C@206564e9>
user=> (-> (.put cb " Dragons") (.array) (String.))
"There Be Dragons"
答案 5 :(得分:0)
如果你想要性能,我不会使用StringBuilder或创建一个byte []。相反,您可以逐步写入将首先获取数据的流。如果你不能这样做,你可以将数据从StringBuilder复制到Writer,但是首先不创建StringBuilder要快得多。