Tôi muốn chuyển đổi một mảng ký tự thành một mảng byte trong Java. Có những phương pháp nào để thực hiện chuyển đổi này?
Tôi muốn chuyển đổi một mảng ký tự thành một mảng byte trong Java. Có những phương pháp nào để thực hiện chuyển đổi này?
Câu trả lời:
char[] ch = ?
new String(ch).getBytes();
hoặc là
new String(ch).getBytes("UTF-8");
để có được bộ ký tự không mặc định.
Cập nhật: Kể từ Java 7:new String(ch).getBytes(StandardCharsets.UTF_8);
Chuyển đổi mà không cần tạo String
đối tượng:
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;
}
Sử dụng:
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
Giải pháp được lấy cảm hứng từ đề xuất Swing để lưu trữ mật khẩu trong char []. (Xem Tại sao char [] được ưu tiên hơn Chuỗi cho mật khẩu? )
Hãy nhớ không ghi dữ liệu nhạy cảm vào nhật ký và đảm bảo rằng JVM sẽ không giữ bất kỳ tham chiếu nào đến nó.
Đoạn mã trên là đúng nhưng không hiệu quả. Nếu bạn không cần hiệu suất nhưng muốn bảo mật, bạn có thể sử dụng nó. Nếu bảo mật cũng không phải là một mục tiêu thì hãy làm đơn giản String.getBytes
. Mã trên không hiệu quả nếu bạn xem thường việc triển khai encode
trong JDK. Bên cạnh đó bạn cần sao chép mảng và tạo bộ đệm. Một cách khác để chuyển đổi là nội tuyến tất cả mã phía sau encode
(ví dụ cho 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"))
Xin lỗi vì đã sử dụng ngôn ngữ Scala. Nếu bạn gặp vấn đề với việc chuyển đổi mã này sang Java, tôi có thể viết lại nó. Điều gì về hiệu suất luôn luôn kiểm tra trên dữ liệu thực (với JMH chẳng hạn). Mã này trông rất giống với những gì bạn có thể thấy trong JDK [ 2 ] và Protobuf [ 3 ].
Câu trả lời của Andrey (được bình chọn cao nhất tại thời điểm viết bài) hơi không chính xác. Tôi đã có thể thêm điều này như bình luận nhưng tôi không đủ uy tín.
Trong câu trả lời của Andrey:
char[] chars = {'c', 'h', 'a', 'r', 's'}
byte[] bytes = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)).array();
lệnh gọi tới array () có thể không trả về giá trị mong muốn, ví dụ:
char[] c = "aaaaaaaaaa".toCharArray();
System.out.println(Arrays.toString(Charset.forName("UTF-8").encode(CharBuffer.wrap(c)).array()));
đầu ra:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0]
Như có thể thấy một byte 0 đã được thêm vào. Để tránh điều này, hãy sử dụng như sau:
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));
đầu ra:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97]
Vì câu trả lời cũng ám chỉ đến việc sử dụng mật khẩu, có thể đáng để xóa mảng hỗ trợ ByteBuffer (được truy cập thông qua hàm 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()
trả về bất kỳ thứ gì khác với 1 (tôi nhận được 1.1). Không quan tâm bạn đang sử dụng hệ điều hành / vòm nào khi tôi kiểm tra kỹ với oracle 1.7.0_51 và openjdk 1.7.0_51 và thấy nó bị hỏng với 10 ký tự.
buffer.array()
trong toBytes
hàm vẫn cần ghi đè, hiện tại chỉ có bản sao.
Bạn có thể thực hiện một phương pháp:
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;
}
Hi vọng điêu nay co ich