Я хотел бы преобразовать массив символов в массив байтов в Java. Какие существуют методы для этого преобразования?
Я хотел бы преобразовать массив символов в массив байтов в Java. Какие существуют методы для этого преобразования?
Ответы:
char[] ch = ?
new String(ch).getBytes();
или же
new String(ch).getBytes("UTF-8");
чтобы получить кодировку не по умолчанию.
Обновление: начиная с Java 7:new String(ch).getBytes(StandardCharsets.UTF_8);
Преобразовать без создания 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 ].
Ответ Андрея (наибольшее количество голосов на момент написания) несколько неверен. Я бы добавил это в качестве комментария, но я недостаточно уважаемый.
В ответ Андрея:
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));
averageBytesPerChar()вернет что-либо, кроме 1 (я получаю 1.1). Из интереса, какую ОС / арку вы используете, поскольку я дважды проверил с помощью oracle 1.7.0_51 и openjdk 1.7.0_51 и обнаружил, что он сломан с 10 символами.
buffer.array()в toBytesфункции все еще нужно переопределить, в настоящее время только копия.
Вы можете сделать метод:
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;
}
Надеюсь это поможет