char []를 byte []로 변환


답변:


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

또는

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

기본이 아닌 문자 집합을 가져옵니다.

업데이트 : Java 7부터new String(ch).getBytes(StandardCharsets.UTF_8);


4
플랫폼의 기본 문자 집합을 사용하는 것은 대부분의 경우 잘못되었습니다 (웹 앱).
maaartinus 2011

4
새 문자열을 사용하기 때문에 작업에 필요한 공간이 두 배가되기 때문에 이것은 사소한 해결책입니다. 매우 큰 입력에는 잘 작동하지 않습니다.
Levent Divilioglu

167

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 []이 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 ] 에서 볼 수있는 것과 매우 유사합니다 .


이것은 ByteBuffer를 생성하지 않습니까? String 개체보다 비용이 적게 듭니다.
Andi Jay

15
@CrazyJay 나는이 방법이 문자열 풀에 "문자"를 저장하지 않을 것이라고 믿습니다. 이렇게하면 암호 데이터를보다 안전하게 사용할 수 있습니다.
Andrii Nemchenko 2012-07-03

1
@Cassian 방법이 잘못 작동합니다. 읽기는 여기에 세부 stackoverflow.com/a/20604909/355491
안드리 Nemchenko에게

1
@Prabs 아니요, 하나의 UTF-8 문자는 1-4 바이트입니다. 하나의 ASCII 문자도 8 비트를 사용합니다.
Andrii Nemchenko

1
이 'toBytes ()'메서드는 중요한 부작용이 있습니다. 입력 문자를 지 웁니다. charBuffer.array ()는 실제로 입력 문자입니다. Arrays.fill ()은 실제로 입력을 지울 것입니다. 대부분의 경우 괜찮지 만 때때로 원하지 않는 효과를 생성합니다.
Guangliang

19

편집 : Andrey의 답변이 업데이트되어 다음이 더 이상 적용되지 않습니다.

Andrey의 답변 (작성 당시 가장 많이 득표 한 답변)은 약간 잘못되었습니다. 나는 이것을 주석으로 추가했을 것이지만 충분히 평판이 좋지는 않습니다.

Andrey의 대답에서 :

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]

보시다시피 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));

후행 \ 0은 구현에 따라 다를 수 있습니까? netbeans 7.4와 함께 1.7_51을 사용하고 있으며 후행 \ 0을 알아 차리지 않습니다.

@orthopteroid yes이 예제는 jvm에 따라 다를 수 있습니다. 이것은 oracle 1.7.0_45 linux 64 비트 (메모리에서)로 실행되었습니다. 다음 구현 ( grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… )을 사용하면 averageBytesPerChar()1이 아닌 다른 값을 반환 하면 오류가 발생 합니다 (1.1이 표시됨). 흥미롭게도 oracle 1.7.0_51 및 openjdk 1.7.0_51로 두 번 확인하고 10 자로 깨진 것을 발견했을 때 어떤 OS / 아치를 사용하고 있습니까?
djsutho

@Andrey 걱정 마세요. 참고 buffer.array()toBytes기능을 여전히 오버라이드 (override) 할 필요는, 현재는 복사입니다.
djsutho

@Andrey 나는 변경 사항을 반영하기 위해 내 대답을 편집했습니다.
djsutho

@djsutho 오늘 내 플랫폼은 windows7x64입니다. 죄송합니다. 코드를 표시 할 수 없습니다. "System.arraycopy (str.getBytes ("UTF-8 "), 0, stor, 0, used);"와 같은 코드를 사용하고 있습니다. 지금.

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

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

도움이 되었기를 바랍니다


4
char 데이터가 유니 코드이고 문자 당 최대 4 바이트가있을 수 있기 때문에이 대답은 올바르지 않습니다 (더 많은 것이 가능하지만 실제로는 최대 4 바이트 만 찾았습니다). 단순히 각 문자에서 1 바이트를 취하는 것은 매우 제한된 문자 집합에서만 작동합니다. joelonsoftware.com/articles/Unicode.html 에서 '모든 소프트웨어 개발자는 절대적으로 유니 코드 및 문자 집합에 대해 반드시 알아야합니다 (변명 없음!)'를 읽어보십시오 .
Ilane 2014 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.