java 从 byte[] 创建 StringBuilder
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11115082/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Create StringBuilder from byte[]
提问by Mickael Marrache
Is there a way to create a StringBuilder
from a byte[]
?
有没有办法StringBuilder
从 a创建a byte[]
?
I want to improve memory usage using StringBuilder
but what I have first is a byte[]
, so I have to create a String
from the byte[]
and then create the StringBuilder
from the String
and I don't see this solution as optimal.
我想用,提高内存的使用情况StringBuilder
,但我必须首先是一个byte[]
,所以我必须要创建一个String
从byte[]
,然后创建StringBuilder
从String
我不把这个解决方案是最佳的。
Thanks
谢谢
回答by bezmax
Basically, your best option seems to be using CharsetDecoderdirectly.
基本上,您最好的选择似乎是直接使用CharsetDecoder。
Here's how:
就是这样:
byte[] srcBytes = getYourSrcBytes();
//Whatever charset your bytes are endoded in
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
//ByteBuffer.wrap simply wraps the byte array, it does not allocate new memory for it
ByteBuffer srcBuffer = ByteBuffer.wrap(srcBytes);
//Now, we decode our srcBuffer into a new CharBuffer (yes, new memory allocated here, no can do)
CharBuffer resBuffer = decoder.decode(srcBuffer);
//CharBuffer implements CharSequence interface, which StringBuilder fully support in it's methods
StringBuilder yourStringBuilder = new StringBuilder(resBuffer);
ADDED:
添加:
After some tests it seems that the simple new String(bytes)
is much faster and it seems there is no simple way to make it faster than that. Here is the test I ran:
经过一些测试,似乎 simplenew String(bytes)
快得多,而且似乎没有比这更快的简单方法。这是我运行的测试:
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.text.ParseException;
public class ConsoleMain {
public static void main(String[] args) throws IOException, ParseException {
StringBuilder sb1 = new StringBuilder("abcdefghijklmnopqrstuvwxyz");
for (int i=0;i<19;i++) {
sb1.append(sb1);
}
System.out.println("Size of buffer: "+sb1.length());
byte[] src = sb1.toString().getBytes("UTF-8");
StringBuilder res;
long startTime = System.currentTimeMillis();
res = testStringConvert(src);
System.out.println("Conversion using String time (msec): "+(System.currentTimeMillis()-startTime));
if (!res.toString().equals(sb1.toString())) {
System.err.println("Conversion error");
}
startTime = System.currentTimeMillis();
res = testCBConvert(src);
System.out.println("Conversion using CharBuffer time (msec): "+(System.currentTimeMillis()-startTime));
if (!res.toString().equals(sb1.toString())) {
System.err.println("Conversion error");
}
}
private static StringBuilder testStringConvert(byte[] src) throws UnsupportedEncodingException {
String s = new String(src, "UTF-8");
StringBuilder b = new StringBuilder(s);
return b;
}
private static StringBuilder testCBConvert(byte[] src) throws CharacterCodingException {
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
ByteBuffer srcBuffer = ByteBuffer.wrap(src);
CharBuffer resBuffer = decoder.decode(srcBuffer);
StringBuilder b = new StringBuilder(resBuffer);
return b;
}
}
Results:
结果:
Size of buffer: 13631488
Conversion using String time (msec): 91
Conversion using CharBuffer time (msec): 252
And a modified (less memory-consuming) version on IDEONE: Here.
IDEONE 上的修改(较少内存消耗)版本:这里。
回答by MvG
If it is short statements you want, then there is no way around the String step in between. The String constructor mixes conversion and object construction for convenience in a very common case, but there is no such convenience constructor for a StringBuilder.
如果它是您想要的简短语句,那么就无法绕过中间的 String 步骤。在非常常见的情况下,为方便起见,String 构造函数混合了转换和对象构造,但 StringBuilder 没有这种方便的构造函数。
If it is performance you are interested in, then you might avoid the intermediate String object by using something like this:
如果您对性能感兴趣,那么您可以通过使用以下内容来避免中间 String 对象:
new StringBuilder(Charset.forName(charsetName).decode(ByteBuffer.wrap(inBytes)))
If you want to be able to fine-tune performance, you can control the decode process yourself. For example, you might want to avoid using too much memory, by using averageCharsPerByte as an estimate of how much memory will be needed. Instead of resizing the buffer if that estimate was too short, you could use the resulting StringBuilder to accumulate all the parts.
如果您希望能够微调性能,您可以自己控制解码过程。例如,您可能希望避免使用过多内存,方法是使用 averageCharsPerByte 作为对需要多少内存的估计。如果估计值太短,则不必调整缓冲区的大小,您可以使用生成的 StringBuilder 来累积所有部分。
CharsetDecoder cd = Charset.forName(charsetName).newDecoder();
cd.onMalformedInput(CodingErrorAction.REPLACE);
cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
int lengthEstimate = Math.ceil(cd.averageCharsPerByte()*inBytes.length) + 1;
ByteBuffer inBuf = ByteBuffer.wrap(inBytes);
CharBuffer outBuf = CharBuffer.allocate(lengthEstimate);
StringBuilder out = new StringBuilder(lengthEstimate);
CoderResult cr;
while (true) {
cr = cd.decode(inBuf, outBuf, true);
out.append(outBuf);
outBuf.clear();
if (cr.isUnderflow()) break;
if (!cr.isOverflow()) cr.throwException();
}
cr = cd.flush(outBuf);
if (!cr.isUnderflow()) cr.throwException();
out.append(outBuf);
I doubt that the above code will be worth the effort in most applications, though. If an application is that interested in performance, it probably shouldn't be dealing with StringBuilder either, but handle everything at the buffer level.
不过,我怀疑上面的代码在大多数应用程序中是否值得付出努力。如果应用程序对性能感兴趣,它可能也不应该处理 StringBuilder,而是在缓冲区级别处理所有内容。