Подтвердить что ты не робот

Преобразование char [] в байт []

Я хотел бы преобразовать массив символов в массив байтов в Java. Какие существуют методы для преобразования?

4b9b3361

Ответ 1

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

или

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

чтобы получить кодировку не по умолчанию.

Обновление: Так как Java 7: new String(ch).getBytes(StandardCharsets.UTF_8);

Ответ 2

Преобразовать без создания объекта 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 []. (См. Почему char [] предпочтительнее, чем String для паролей?)

Не забывайте записывать конфиденциальные данные в журналы и убедитесь, что 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"))

Извините за использование языка Scala. Если у вас есть проблемы с преобразованием этого кода в Java, я могу переписать его. Что касается производительности, всегда проверяйте реальные данные (например, с помощью JMH). Этот код выглядит очень похоже на то, что вы можете увидеть в JDK [ 2 ] и Protobuf [ 3 ].

Ответ 3

Изменить: ответ Andrey обновлен, поэтому больше не применяется.

Ответ Andrey (самый высокий, который был проголосован на момент написания), немного неверен. Я бы добавил это как комментарий, но я не достаточно авторитетным.

В ответ Андрей:

char[] chars = {'c', 'h', 'a', 'r', 's'}
byte[] bytes = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)).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));

Ответ 4

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

Ответ 5

Фактически char и байт могут иметь разный размер в Java, так как char может содержать любой символ Юникода, который может достигать 16 бит.

Ответ 6

Вы можете сделать способ:

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

Надеюсь, что это поможет