标题说明了一切。有什么方法可以在不使用中间字符串的情况下从 StringBuilder 转换为 byte[] ?
问题是我正在管理非常大的字符串(数百万个字符),然后我有一个循环,最后添加一个字符并获取字节 []。将 StringBuffer 转换为 String 的过程使得这个循环非常非常非常缓慢。
有没有办法做到这一点?提前致谢!
标题说明了一切。有什么方法可以在不使用中间字符串的情况下从 StringBuilder 转换为 byte[] ?
问题是我正在管理非常大的字符串(数百万个字符),然后我有一个循环,最后添加一个字符并获取字节 []。将 StringBuffer 转换为 String 的过程使得这个循环非常非常非常缓慢。
有没有办法做到这一点?提前致谢!
正如许多人已经建议的那样,您可以使用 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;
如果您愿意StringBuilder
用其他东西替换,另一种可能性是Writer
由 a 支持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());
与往常一样,您的里程可能会有所不同。
不幸的是,上面处理 ByteBuffer 的 array() 方法的答案有点错误......问题是分配的 byte[] 可能比您预期的要大。因此,将有难以摆脱的尾随 NULL 字节,因为您无法在 Java 中“重新调整”数组的大小。
这是一篇更详细地解释这一点的文章: http ://worldmodscode.wordpress.com/2012/12/14/the-java-bytebuffer-a-crash-course/
对于初学者,您可能应该使用StringBuilder
,因为StringBuffer
通常不需要同步开销。
不幸的是,没有办法直接转到byte
s,但您可以将 s 复制char
到一个数组中,或者从0
to迭代length()
并读取每个s charAt()
。
如果您想要性能,我不会使用 StringBuilder 或创建字节 []。相反,您可以逐步写入将首先获取数据的流。如果你不能这样做,你可以将数据从 StringBuilder 复制到 Writer,但首先不创建 StringBuilder 会快得多。
你想用“百万个字符”来完成什么?这些日志需要解析吗?您可以将其仅读取为字节并坚持使用ByteBuffer吗?然后你可以这样做:
buffer.array()
得到一个byte[]
取决于你在做什么,你也可以只使用 achar[]
或CharBuffer:
CharBuffer cb = CharBuffer.allocate(4242);
cb.put("Depends on what it is you need to do");
...
然后你可以得到一个char[]
:
cp.array()
将事情重新整理出来总是好的,这很有趣并且证明了这一点。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"