Java:没有toString的StringBuffer到byte []

时间:2013-10-19 22:50:40

标签: java string bytearray stringbuffer

标题说明了一切。有没有办法从StringBuilder转换为byte []而不在中间使用String?

问题是我管理的是真正的大字符串(数百万个字符),然后我有一个循环,最后添加一个字符并获得字节[]。将StringBuffer转换为String的过程使得这个循环非常非常慢。

有没有办法实现这个目标?提前谢谢!

6 个答案:

答案 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要快得多。