将char []转换为byte []

时间:2011-04-01 12:08:30

标签: java arrays type-conversion

我想在Java中将字符数组转换为字节数组。有哪些方法可以进行此转换?

7 个答案:

答案 0 :(得分:143)

转换而不创建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;
}

用法:

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

解决方案受到Swing建议的启发,将密码存储在char []中。 (见Why is char[] preferred over String for passwords?

请记住,不要将敏感数据写入日志,并确保JVM不会对其进行任何引用。


上面的代码是正确但无效的。如果您不需要性能但需要安全性,则可以使用它。如果安全性也不是目标,那么只需String.getBytes。如果您在JDK中查看encode的实现,则上述代码无效。此外,您需要复制数组并创建缓冲区。另一种转换方式是内联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"))

请原谅我使用Scala语言。如果您将此代码转换为Java时遇到问题,我可以重写它。性能如何始终检查实际数据(例如,使用JMH)。此代码与您在JDK [2]和Protobuf [3]中看到的代码非常相似。

答案 1 :(得分:69)

char[] ch = ?
new String(ch).getBytes();

new String(ch).getBytes("UTF-8");

获取非默认字符集。

更新:自Java 7以来:new String(ch).getBytes(StandardCharsets.UTF_8);

答案 2 :(得分:17)

编辑:安德烈的答案已更新,因此以下内容不再适用。

安德烈的答案(在撰写本文时投票的最高票数)略有下降 不正确。我会添加这个作为评论,但我不是 信誉良好。

在安德烈的回答中:

char[] chars = {'c', 'h', 'a', 'r', 's'}
byte[] bytes = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)).array();

对array()的调用可能不会返回所需的值,例如:

char[] c = "aaaaaaaaaa".toCharArray();
System.out.println(Arrays.toString(Charset.forName("UTF-8").encode(CharBuffer.wrap(c)).array()));

输出:

[97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0]

可以看到添加了一个零字节。为避免这种情况,请使用以下内容:

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));

输出:

[97, 97, 97, 97, 97, 97, 97, 97, 97, 97]

正如答案也提到使用密码可能是值得的 消隐支持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));

答案 3 :(得分:0)

private static byte[] charArrayToByteArray(char[] c_array) {
        byte[] b_array = new byte[c_array.length];
        for(int i= 0; i < c_array.length; i++) {
            b_array[i] = (byte)(0xFF & (int)c_array[i]);
        }
        return b_array;
}

答案 4 :(得分:0)

如果你只想转换数据容器(数组)类型本身,只考虑数据大小并且不知道任何编码:

// original byte[]
byte[] pattern = null;
char[] arr = new char[pattern.length * 2];
ByteBuffer wrapper = ByteBuffer.wrap(pattern);
wrapper.position(0);
int i = 0;
while(wrapper.hasRemaining()) {
    char character = wrapper.remaining() < 2 ? ((char) (((int) wrapper.get()) << 8)) : wrapper.getChar();
    arr[i++] = character;
}

答案 5 :(得分:-2)

实际上char和byte在Java中可以有不同的大小,因为char可以包含任何Unicode字符,最多可以包含16位。

答案 6 :(得分:-5)

你可以制作一个方法:

public byte[] toBytes(char[] data) {
byte[] toRet = new byte[data.length];
for(int i = 0; i < toRet.length; i++) {
toRet[i] = (byte) data[i];
}
return toRet;
}

希望这有帮助