1. 소개

 Java에서 문자열바이트 배열 사이를 변환해야 하는 경우가 많습니다 . 이 사용방법(예제)에서는 이러한 작업을 자세히 살펴보겠습니다.

먼저 문자열바이트 배열 로 변환하는 다양한 방법을 살펴보겠습니다 . 그런 다음 유사한 작업을 반대로 살펴보겠습니다.

2. 문자열바이트 배열 로 변환

String 은 Java에서 유니코드 문자의 배열로 저장됩니다 바이트 배열 로 변환하기 위해  문자 시퀀스를 바이트 시퀀스로 변환합니다. 이 번역에서는 Charset 인스턴스를 사용합니다 . 이 클래스는 char 시퀀스와 byte 시퀀스 간의 매핑을 지정 합니다 .

위의 과정을 인코딩 이라고 합니다.

Java에서는 여러 가지 방법으로 문자열바이트 배열로 인코딩할 수 있습니다. 예를 들어 각각에 대해 자세히 살펴보겠습니다.

2.1. String.getBytes() 사용 

String 클래스는 String을 바이트 배열로 인코딩하는 세 가지 오버  로드 getBytes 메서드제공 합니다 .

먼저 플랫폼의 기본 문자 집합을 사용하여 문자열을 인코딩해 보겠습니다.

String inputString = "Hello World!";
byte[] byteArrray = inputString.getBytes();

위의 방법은 플랫폼의 기본 문자 집합을 사용하므로 플랫폼에 따라 다릅니다. Charset.defaultCharset() 을 호출하여 이 문자 집합을 얻을 수 있습니다 .

그런 다음 명명된 문자 집합을 사용하여 문자열을 인코딩해 보겠습니다.

@Test
public void whenGetBytesWithNamedCharset_thenOK() 
  throws UnsupportedEncodingException {
    String inputString = "Hello World!";
    String charsetName = "IBM01140";

    byte[] byteArrray = inputString.getBytes("IBM01140");
    
    assertArrayEquals(
      new byte[] { -56, -123, -109, -109, -106, 64, -26,
        -106, -103, -109, -124, 90 },
      byteArrray);
}

이 메서드는 명명된 문자 집합이 지원되지 않는 경우 UnsupportedEncodingException 을 throw합니다.

입력에 charset에서 지원하지 않는 문자가 포함된 경우 위 두 버전의 동작은 정의되지 않습니다. 대조적으로, 세 번째 버전은 지원되지 않는 입력을 인코딩하기 위해 charset의 기본 대체 바이트 배열을 사용합니다.

다음으로 getBytes() 메서드 의 세 번째 버전을 호출하고 Charset 의 인스턴스를 전달해 보겠습니다.

@Test
public void whenGetBytesWithCharset_thenOK() {
    String inputString = "Hello ਸੰਸਾਰ!";
    Charset charset = Charset.forName("ASCII");

    byte[] byteArrray = inputString.getBytes(charset);

    assertArrayEquals(
      new byte[] { 72, 101, 108, 108, 111, 32, 63, 63, 63,
        63, 63, 33 },
      byteArrray);
}

여기서 우리는 Charset 의 인스턴스를 얻기 위해 팩토리 메소드 Charset.forName 을 사용하고 있습니다. 이 메서드는 요청된 문자 집합의 이름이 유효하지 않은 경우 런타임 예외를 throw합니다. 또한 현재 JVM에서 charset이 지원되는 경우 런타임 예외가 발생합니다.

그러나 일부 문자 집합은 모든 Java 플랫폼에서 사용 가능하도록 보장됩니다. StandardCharsets 클래스는 이러한 문자 집합에 대한 상수를 정의합니다.

마지막으로 표준 문자 집합 중 하나를 사용하여 인코딩해 보겠습니다.

@Test
public void whenGetBytesWithStandardCharset_thenOK() {
    String inputString = "Hello World!";
    Charset charset = StandardCharsets.UTF_16;

    byte[] byteArrray = inputString.getBytes(charset);

    assertArrayEquals(
      new byte[] { -2, -1, 0, 72, 0, 101, 0, 108, 0, 108, 0,
        111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 33 },
      byteArrray);
}

이로써 다양한 getBytes 버전 에 대한 검토를 완료했습니다 . 다음으로 Charset  자체 에서 제공하는 메소드를 살펴보겠습니다 .

2.2. Charset.encode() 사용 

Charset 클래스  는 유니코드 문자를 바이트로 인코딩하는 편리한 메서드인 encode()를 제공 합니다 . 이 메서드는 항상 문자 집합의 기본 대체 바이트 배열을 사용하여 잘못된 입력 및 매핑할 수 없는 문자를 대체합니다.

인코딩 방법을 사용하여 문자열바이트 배열 로 변환해 보겠습니다 .

@Test
public void whenEncodeWithCharset_thenOK() {
    String inputString = "Hello ਸੰਸਾਰ!";
    Charset charset = StandardCharsets.US_ASCII;

    byte[] byteArrray = charset.encode(inputString).array();

    assertArrayEquals(
      new byte[] { 72, 101, 108, 108, 111, 32, 63, 63, 63, 63, 63, 33 },
      byteArrray);
}

위에서 볼 수 있듯이 지원되지 않는 문자는 문자 집합의 기본 대체  바이트 63으로 대체되었습니다.

지금까지 사용한 접근 방식은 내부적으로 CharsetEncoder 클래스를 사용하여 인코딩을 수행합니다. 다음 섹션에서 이 클래스를 살펴보겠습니다.

2.3. CharsetEncoder

CharsetEncoder 는 유니코드 문자를 주어진 charset에 대한 바이트 시퀀스로 변환합니다 . 또한 인코딩 프로세스를 세밀하게 제어할 수 있습니다 .

이 클래스를 사용하여 String바이트 배열로 변환해 보겠습니다.

@Test
public void whenUsingCharsetEncoder_thenOK()
  throws CharacterCodingException {
    String inputString = "Hello ਸੰਸਾਰ!";
    CharsetEncoder encoder = StandardCharsets.US_ASCII.newEncoder();
    encoder.onMalformedInput(CodingErrorAction.IGNORE)
      .onUnmappableCharacter(CodingErrorAction.REPLACE)
      .replaceWith(new byte[] { 0 });

    byte[] byteArrray = encoder.encode(CharBuffer.wrap(inputString))
                          .array();

    assertArrayEquals(
      new byte[] { 72, 101, 108, 108, 111, 32, 0, 0, 0, 0, 0, 33 },
      byteArrray);
}

여기에서는 Charset 개체 에서 newEncoder  메서드를 호출하여 CharsetEncoder 의 인스턴스를 만듭니다.

그런 다음 onMalformedInput()onUnmappableCharacter()  메서드 를 호출하여 오류 조건에 대한 작업을 지정 합니다 .  다음 작업을 지정할 수 있습니다.

또한, 대체 바이트 배열 을 지정하기 위해 replaceWith() 메서드를 사용하고 있습니다.

따라서 문자열을 바이트 배열로 변환하는 다양한 접근 방식에 대한 검토를 완료했습니다. 다음으로 역동작을 살펴보자.

3. 바이트 배열을 문자열로 변환

바이트 배열을 문자열변환하는 과정을 디코딩 이라고 합니다. 인코딩과 유사하게 이 프로세스에는 Charset 이 필요합니다 .

그러나 바이트 배열을 디코딩하는 데 문자 집합을 사용할 수는 없습니다. 특히, String  을 바이트 배열 로 인코딩한 charset을 사용해야 합니다 .

또한 여러 가지 방법으로 바이트 배열을 문자열로 변환할 수 있습니다. 각각에 대해 자세히 살펴보겠습니다.

3.1. 문자열 생성자 사용

String 클래스 에는 바이트 배열을 입력으로 사용하는 몇 가지 생성자가 있습니다 . 그것들은 모두 getBytes 메소드와 유사하지만 역으로 작동합니다.

플랫폼의 기본 문자 집합을 사용하여 바이트 배열을 String 으로 변환해 보겠습니다.

@Test
public void whenStringConstructorWithDefaultCharset_thenOK() {
    byte[] byteArrray = { 72, 101, 108, 108, 111, 32, 87, 111, 114,
      108, 100, 33 };
    
    String string = new String(byteArrray);
    
    assertNotNull(string);
}

여기에서는 디코딩된 문자열의 내용에 대해 아무 것도 주장하지 않습니다. 플랫폼의 기본 문자 집합에 따라 다른 것으로 디코딩될 수 있기 때문입니다.

이러한 이유로 일반적으로 이 방법을 피해야 합니다.

그런 다음 디코딩을 위해 명명된 charset을 사용하겠습니다.

@Test
public void whenStringConstructorWithNamedCharset_thenOK()
    throws UnsupportedEncodingException {
    String charsetName = "IBM01140";
    byte[] byteArrray = { -56, -123, -109, -109, -106, 64, -26, -106,
      -103, -109, -124, 90 };

    String string = new String(byteArrray, charsetName);
        
    assertEquals("Hello World!", string);
}

JVM에서 명명된 charset을 사용할 수 없는 경우 이 메서드는 예외를 throw합니다.

다음 으로 Charset 개체를 사용하여 디코딩을 수행해 보겠습니다 .

@Test
public void whenStringConstructorWithCharSet_thenOK() {
    Charset charset = Charset.forName("UTF-8");
    byte[] byteArrray = { 72, 101, 108, 108, 111, 32, 87, 111, 114,
      108, 100, 33 };

    String string = new String(byteArrray, charset);

    assertEquals("Hello World!", string);
}

마지막으로 동일한 표준 Charset 을 사용하겠습니다.

@Test
public void whenStringConstructorWithStandardCharSet_thenOK() {
    Charset charset = StandardCharsets.UTF_16;
        
    byte[] byteArrray = { -2, -1, 0, 72, 0, 101, 0, 108, 0, 108, 0,
      111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 33 };

    String string = new String(byteArrray, charset);

    assertEquals("Hello World!", string);
}

지금까지 생성자를 사용하여 바이트 배열을 String 으로 변환 했으며 이제 다른 접근 방식을 살펴보겠습니다.

3.2. Charset.decode() 사용 

Charset 클래스는 ByteBufferString 으로 변환하는 decode() 메서드를 제공 합니다 .

@Test
public void whenDecodeWithCharset_thenOK() {
    byte[] byteArrray = { 72, 101, 108, 108, 111, 32, -10, 111,
      114, 108, -63, 33 };
    Charset charset = StandardCharsets.US_ASCII;
    String string = charset.decode(ByteBuffer.wrap(byteArrray))
                      .toString();

    assertEquals("Hello �orl�!", string);
}

여기서 잘못된 입력은 charset의 기본 대체 문자로 대체됩니다.

3.3. CharsetDecoder

내부적으로 디코딩하기 위한 이전의 모든 접근 방식은 CharsetDecoder  클래스를 사용합니다. 디코딩 프로세스에 대한 세분화된 제어를 위해 이 클래스를 직접 사용할 수 있습니다 .

@Test
public void whenUsingCharsetDecoder_thenOK()
  throws CharacterCodingException {
    byte[] byteArrray = { 72, 101, 108, 108, 111, 32, -10, 111, 114,
      108, -63, 33 };
    CharsetDecoder decoder = StandardCharsets.US_ASCII.newDecoder();

    decoder.onMalformedInput(CodingErrorAction.REPLACE)
      .onUnmappableCharacter(CodingErrorAction.REPLACE)
      .replaceWith("?");

    String string = decoder.decode(ByteBuffer.wrap(byteArrray))
                      .toString();

    assertEquals("Hello ?orl?!", string);
}

여기서 유효하지 않은 입력과 지원되지 않는 문자를 "?"로 교체합니다.

유효하지 않은 입력의 경우 알림을 받으려면 디코더 를 변경할 수 있습니다 .

decoder.onMalformedInput(CodingErrorAction.REPORT)
  .onUnmappableCharacter(CodingErrorAction.REPORT)

4. 결론

이 기사에서는 문자열 을 바이트 배열로 또는 그 반대로 변환하는 여러 방법을 조사했습니다. 잘못된 입력에 필요한 제어 수준뿐만 아니라 입력 데이터를 기반으로 적절한 방법을 선택해야 합니다.

평소와 같이 전체 소스 코드는  GitHub 에서 찾을 수 있습니다 .

Generic footer banner