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
ソリューションは、パスワードをchar []に保存するというSwingの推奨事項から着想を得ています。 ( パスワードの文字列よりもchar []が好ましい理由は? を参照)
機密データをログに書き込まないでください。また、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 []で見られるものと非常によく似ています。
アンドレイの答え(執筆時点で最高の票)はわずかに間違っています。これをコメントとして追加しますが、十分に評判がよくありません。
アンドレイの答え:
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));
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;
}