And*_*nko 151
转换而不创建String对象:
import java.nio.CharBuffer;
import java.nio.ByteBuffer;
import java.util.Arrays;
byte[] toBytes(char[] chars) {
CharBuffer charBuffer = CharBuffer.wrap(chars);
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
byte[] bytes = Arrays.copyOfRange(byteBuffer.array(),
byteBuffer.position(), byteBuffer.limit());
Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
return bytes;
}
Run Code Online (Sandbox Code Playgroud)
用法:
char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
byte[] bytes = toBytes(chars);
/* do something with chars/bytes */
Arrays.fill(chars, '\u0000'); // clear sensitive data
Arrays.fill(bytes, (byte) 0); // clear sensitive data
Run Code Online (Sandbox Code Playgroud)
解决方案的灵感来自于Swing建议将密码存储在char []中.(有关密码,请参阅为什么char []优先于字符串?)
切记不要将敏感数据写入日志,并确保JVM不会保留对它的任何引用.
上面的代码是正确的但无效.如果您不需要性能但需要安全性,则可以使用它.如果安全性也不是目标那么简单String.getBytes.如果你encode忽视JDK 的实现,上面的代码是无效的.此外,您需要复制数组并创建缓冲区.转换的另一种方法是内联所有代码encode(UTF-8的示例):
val xs: Array[Char] = "A ß € ? ".toArray
val len = xs.length
val ys: Array[Byte] = new Array(3 * len) // worst case
var i = 0; var j = 0 // i for chars; j for bytes
while (i < len) { // fill ys with bytes
val c = xs(i)
if (c < 0x80) {
ys(j) = c.toByte
i = i + 1
j = j + 1
} else if (c < 0x800) {
ys(j) = (0xc0 | (c >> 6)).toByte
ys(j + 1) = (0x80 | (c & 0x3f)).toByte
i = i + 1
j = j + 2
} else if (Character.isHighSurrogate(c)) {
if (len - i < 2) throw new Exception("overflow")
val d = xs(i + 1)
val uc: Int =
if (Character.isLowSurrogate(d)) {
Character.toCodePoint(c, d)
} else {
throw new Exception("malformed")
}
ys(j) = (0xf0 | ((uc >> 18))).toByte
ys(j + 1) = (0x80 | ((uc >> 12) & 0x3f)).toByte
ys(j + 2) = (0x80 | ((uc >> 6) & 0x3f)).toByte
ys(j + 3) = (0x80 | (uc & 0x3f)).toByte
i = i + 2 // 2 chars
j = j + 4
} else if (Character.isLowSurrogate(c)) {
throw new Exception("malformed")
} else {
ys(j) = (0xe0 | (c >> 12)).toByte
ys(j + 1) = (0x80 | ((c >> 6) & 0x3f)).toByte
ys(j + 2) = (0x80 | (c & 0x3f)).toByte
i = i + 1
j = j + 3
}
}
// check
println(new String(ys, 0, j, "UTF-8"))
Run Code Online (Sandbox Code Playgroud)
请原谅我使用Scala语言.如果您将此代码转换为Java时遇到问题,我可以重写它.性能如何始终检查实际数据(例如,使用JMH).这段代码与JDK [ 2 ]和Protobuf [ 3 ]中的代码非常相似.
Tar*_*log 71
char[] ch = ?
new String(ch).getBytes();
Run Code Online (Sandbox Code Playgroud)
要么
new String(ch).getBytes("UTF-8");
Run Code Online (Sandbox Code Playgroud)
得到非默认的字符集.
更新:自Java 7以来:new String(ch).getBytes(StandardCharsets.UTF_8);
djs*_*tho 18
安德烈的答案(在撰写本文时投票的最高票)略有不正确.我会添加这个作为评论,但我不够信誉.
在安德烈的回答中:
char[] chars = {'c', 'h', 'a', 'r', 's'}
byte[] bytes = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)).array();
Run Code Online (Sandbox Code Playgroud)
对array()的调用可能不会返回所需的值,例如:
char[] c = "aaaaaaaaaa".toCharArray();
System.out.println(Arrays.toString(Charset.forName("UTF-8").encode(CharBuffer.wrap(c)).array()));
Run Code Online (Sandbox Code Playgroud)
输出:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0]
Run Code Online (Sandbox Code Playgroud)
可以看出,添加了一个零字节.为避免这种情况,请使用以
char[] c = "aaaaaaaaaa".toCharArray();
ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(c));
byte[] b = new byte[bb.remaining()];
bb.get(b);
System.out.println(Arrays.toString(b));
Run Code Online (Sandbox Code Playgroud)
输出:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97]
Run Code Online (Sandbox Code Playgroud)
由于答案也提到使用密码,因此可能需要消除支持ByteBuffer的数组(通过array()函数访问):
ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(c));
byte[] b = new byte[bb.remaining()];
bb.get(b);
blankOutByteArray(bb.array());
System.out.println(Arrays.toString(b));
Run Code Online (Sandbox Code Playgroud)