바이트 배열을 문자열로 변환하거나 그 반대로 변환하는 방법은 무엇입니까?


248

안드로이드에서 바이트 배열을 문자열로 변환해야하지만 바이트 배열에 음수 값이 있습니다.

해당 문자열을 다시 바이트 배열로 변환하면 얻는 값이 원래 바이트 배열 값과 다릅니다.

적절한 전환을 얻으려면 어떻게해야합니까? 변환에 사용하는 코드는 다음과 같습니다.

// Code to convert byte arr to str:
byte[] by_original = {0,1,-2,3,-4,-5,6};
String str1 = new String(by_original);
System.out.println("str1 >> "+str1);

// Code to convert str to byte arr:
byte[] by_new = str1.getBytes();
for(int i=0;i<by_new.length;i++) 
System.out.println("by1["+i+"] >> "+str1);

나는이 문제에 갇혀있다.


3
왜 임의의 이진 데이터를 문자열로 변환하려고합니까? 답변에서 이미 언급 한 모든 문자 집합 문제 외에도이 작업을 수행하면 문자열을 남용한다는 사실도 있습니다. byte[]이진 데이터와 String텍스트에 a 를 사용하면 무엇이 문제입니까 ?
Joachim Sauer

8
@Joachim-때로는 문자열 저장과 같은 작업을 수행 할 수있는 외부 도구가 있습니다. 이 경우 바이트 배열을 (어떤 방식으로 인코딩 된) 문자열로 바꿀 수 있기를 원합니다.
James Moore

답변:


377

바이트 배열에는 인코딩이 있어야합니다. 음수 값이 있으면 인코딩은 ASCII 일 수 없습니다. 일단 알아 낸 후에는 다음을 사용하여 바이트 세트를 문자열로 변환 할 수 있습니다.

byte[] bytes = {...}
String str = new String(bytes, "UTF-8"); // for UTF-8 encoding

사용할 수있는 인코딩이 많이 있습니다 .Sun javadocs 의 Charset 클래스를보십시오 .


4
@MauricePerry 왜 작동하지 않는지 설명 할 수 UTF-8있습니까?
Asif Mushtaq

12
UTF-8은 일부 문자를 2 바이트 또는 3 바이트 문자열로 인코딩하기 때문에 @UnKnown. 모든 바이트 배열이 유효한 UTF-8 인코딩 문자열은 아닙니다. ISO-8859-1이 더 나은 선택입니다. 여기서 각 문자는 바이트로 인코딩됩니다.
모리스 페리

1
이것은 효과가 있지만 String 생성자를 사용하지 마십시오.
hfontanez 2016 년

1 바이트를 하나의 문자 (8859-1)에 매핑하고 예외 처리 (nio.charset)는 없음 :String str = new String(bytes, java.nio.charset.StandardCharsets.ISO_8859_1);
iman

1
Java 1.7부터는 새로운 String (bytes, StandardCharsets.UTF_8)을 사용할 수 있습니다
ihebiheb

101

사이의 "적절한 변환" byte[]하고 String명시 적으로 사용할 인코딩 상태입니다. a로 시작 byte[]하는데 실제로 텍스트 데이터가 포함되어 있지 않으면 "적절한 변환" 이 없습니다 . Strings는 텍스트, byte[]이진 데이터를위한 것이며, 실제로해야 할 유일한 일은 당신이 절대로 할 필요가 없다면, 그것들 사이의 변환 을 피하는 것입니다.

String바이너리 데이터를 보유하기 위해 실제로 a 를 사용해야하는 경우 가장 안전한 방법은 Base64 인코딩 을 사용 하는 것입니다.


1
예, 문자 인코딩은 문자열과 바이트 사이를 변환하기 위해 알아야 할 것 입니다.
Raedwald

4
Base64 그리고 당신은 내 생명을 구했습니다
mstzn

2
Base64 인코딩으로 내 문제가 해결되었습니다. UTF-8은 모든 입력에 대해 작동하지 않았습니다
Al-Alamin

37

근본적인 문제는 당신이 무의식적으로 다음과 같은 문자 세트를 사용하고 있다는 것입니다.

 bytes != encode(decode(bytes))

일부 경우에. UTF-8은 이러한 문자 집합의 예입니다. 특히, 특정 바이트 시퀀스는 UTF-8에서 유효한 인코딩이 아닙니다. UTF-8 디코더가 이러한 시퀀스 중 하나를 발견하면 문제가되는 바이트를 버리고 "그러한 문자 없음"에 대한 유니 코드 코드 포인트로 디코딩 할 수 있습니다. 당연히 문자를 바이트로 인코딩하려고하면 결과가 달라집니다.

해결책은 다음과 같습니다.

  1. 사용중인 문자 인코딩에 대해 명시하십시오. 즉 String.toByteArray, 명시 적 문자셋과 함께 String 생성자와 메소드를 사용하십시오 .
  2. 바이트 데이터에 올바른 문자 세트를 사용하십시오. 또는 대안으로 모든 바이트 시퀀스가 ​​유효한 유니 코드 문자에 매핑되는 "Latin-1"과 같은 것을 사용하십시오.
  3. 당신의 바이트 (정말) 이진 데이터이고, 당신이 전송을 할 수 있도록하려면 / A "를 기반으로 텍스트"를 통해 그들을 수신 채널, Base64 인코딩 ... 같은 사용 뭔가 이 목적을 위해 설계되었습니다 .

1
"Latin-1"인코딩을 사용해 주셔서 감사합니다!
Gonzo

31

우리 String는 배열 로 새로운 것을 만들어야합니다 : http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/

String s = new String(bytes);

결과 문자열의 바이트는 사용하는 문자 집합에 따라 다릅니다. String #을 호출하면 new String (bytes)과 new String (bytes, Charset.forName ( "utf-8"))과 new String (bytes, Charset.forName ( "utf-16"))은 모두 다른 바이트 배열을 갖습니다. getBytes () (기본 문자 집합에 따라 다름)


9
아니요. 결과 문자열의 바이트 수는 사용하는 문자 집합에 따라 다릅니다. new String(bytes)new String(bytes, Charset.forName("utf-8"))new String(bytes, Charset.forName("utf-16"))당신이 호출 할 때 모든 다른 바이트 배열을해야합니다 String#getBytes()(기본 문자 집합에 따라 다름)
NS 뒤 투아을

1
오해의 소지가 있습니다. 다르게 디코딩 할 때 char결과 의 s (및 표시되는 텍스트)가 다릅니다. 기본 인코딩을 사용하여 바이트로 다시 변환하면 (다른 방법 으로 지정) 다른 입력을 변환하므로 반드시 달라집니다. 문자열 은 만든 문자열을 저장 하지 않으며, 인코딩 이 없으며, 그렇지 않으면 저장하지 않습니다. StringbytesString#getBytes("charset")byte[]charString
zapl

14

사용 new String(byOriginal)하고 다시 변환 byte[]사용 getBytes()이 보장하지 않습니다 byte[]동일한 값을. 이는를 호출하는 것입니다 StringCoding.encode(..)를 인코딩 할 StringCharset.defaultCharset(). 이 인코딩 중에 인코더는 알 수없는 문자를 바꾸고 다른 변경을 수행하도록 선택할 수 있습니다. 따라서을 사용 String.getBytes()하면 원래 생성자에 전달한 것과 동일한 배열이 반환되지 않을 수 있습니다.


9

문제가 발생한 이유 : 누군가가 이미 지정한대로 : byte []로 시작하고 실제로 텍스트 데이터를 포함하지 않으면 "적절한 변환"이 없습니다. 문자열은 텍스트를위한 것이고 byte []는 이진 데이터를위한 것이며, 실제로 할 수있는 유일한 방법은 반드시 필요한 경우가 아니라면 문자열 간 변환을 피하는 것입니다.

pdf 파일에서 byte []를 만든 다음 String으로 변환 한 다음 String을 입력으로 사용하고 파일로 다시 변환하려고 할 때이 문제가 관찰되었습니다.

따라서 인코딩 및 디코딩 논리가 내가했던 것과 동일한 지 확인하십시오. 바이트 []를 Base64로 명시 적으로 인코딩하고 파일을 다시 생성하기 위해 디코딩했습니다.

사용 사례 : 일부 제한으로 인해 전송 byte[]을 시도 request(POST)했으며 프로세스는 다음과 같습니다.

PDF 파일 >> Base64.encodeBase64 (byte []) >> 문자열 >> 요청 전송 (POST) >> 수신 문자열 >> Base64.decodeBase64 (byte []) >> 바이너리 생성

이것을 시도하고 이것은 나를 위해 일했다 ..

File file = new File("filePath");

        byte[] byteArray = new byte[(int) file.length()];

        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            fileInputStream.read(byteArray);

            String byteArrayStr= new String(Base64.encodeBase64(byteArray));

            FileOutputStream fos = new FileOutputStream("newFilePath");
            fos.write(Base64.decodeBase64(byteArrayStr.getBytes()));
            fos.close();
        } 
        catch (FileNotFoundException e) {
            System.out.println("File Not Found.");
            e.printStackTrace();
        }
        catch (IOException e1) {
            System.out.println("Error Reading The File.");
            e1.printStackTrace();
        }

6

이것은 나를 위해 잘 작동합니다 :

String cd="Holding some value";

문자열에서 바이트 []로 변환 :

byte[] cookie = new sun.misc.BASE64Decoder().decodeBuffer(cd);

byte []에서 문자열로 변환 :

cd = new sun.misc.BASE64Encoder().encode(cookie);

5
private static String toHexadecimal(byte[] digest){
        String hash = "";
    for(byte aux : digest) {
        int b = aux & 0xff;
        if (Integer.toHexString(b).length() == 1) hash += "0";
        hash += Integer.toHexString(b);
    }
    return hash;
}

1
이것은 질문에 대답하지 않습니다.
james.garriss

질문에 대답하지 않지만 유용했습니다 +1
Lazy Ninja

5

나는 대답에없는 것을 발견했습니다. 바이트 배열의 각 바이트를 문자로 캐스트하고 char 배열에 넣을 수 있습니다. 그런 다음 문자열은

new String(cbuf)
여기서 cbuf는 char 배열입니다. 다시 변환하려면 각 문자를 바이트로 캐스팅하여 바이트 배열에 넣는 문자열을 반복하십시오.이 바이트 배열은 첫 번째 배열과 같습니다.


public class StringByteArrTest {

    public static void main(String[] args) {
        // put whatever byte array here
        byte[] arr = new byte[] {-12, -100, -49, 100, -63, 0, -90};
        for (byte b: arr) System.out.println(b);
        // put data into this char array
        char[] cbuf = new char[arr.length];
        for (int i = 0; i < arr.length; i++) {
            cbuf[i] = (char) arr[i];
        }
        // this is the string
        String s = new String(cbuf);
        System.out.println(s);

        // converting back
        byte[] out = new byte[s.length()];
        for (int i = 0; i < s.length(); i++) {
            out[i] = (byte) s.charAt(i);
        }
        for (byte b: out) System.out.println(b);
    }

}

2

javax.xml.bind.DatatypeConverter 그것을해야합니다 :

byte [] b = javax.xml.bind.DatatypeConverter.parseHexBinary("E62DB");
String s = javax.xml.bind.DatatypeConverter.printHexBinary(b);

2

다음은 바이트 배열을 문자열로 변환하는 몇 가지 방법입니다. 나는 그들이 잘 작동하는지 테스트했습니다.

public String getStringFromByteArray(byte[] settingsData) {

    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(settingsData);
    Reader reader = new BufferedReader(new InputStreamReader(byteArrayInputStream));
    StringBuilder sb = new StringBuilder();
    int byteChar;

    try {
        while((byteChar = reader.read()) != -1) {
            sb.append((char) byteChar);
        }
    }
    catch(IOException e) {
        e.printStackTrace();
    }

    return sb.toString();

}

public String getStringFromByteArray(byte[] settingsData) {

    StringBuilder sb = new StringBuilder();
    for(byte willBeChar: settingsData) {
        sb.append((char) willBeChar);
    }

    return sb.toString();

}

2

그래도

new String(bytes, "UTF-8")

올바른 경우 UnsupportedEncodingException예외를 처리해야합니다. Java 1.6부터 다른 배열을 다른 생성자로 사용하여 바이트 배열을 다음으로 변환 할 수 있습니다 String.

new String(bytes, StandardCharsets.UTF_8)

이것은 예외를 던지지 않습니다.

다시 변환하려면 다음을 수행해야합니다 StandardCharsets.UTF_8.

"test".getBytes(StandardCharsets.UTF_8)

다시 한 번 확인 된 예외를 처리하지 않아도됩니다.


1

이 방법으로 바이트 배열을 문자열로 변환하는 데 성공했습니다.

public static String byteArrayToString(byte[] data){
    String response = Arrays.toString(data);

    String[] byteValues = response.substring(1, response.length() - 1).split(",");
    byte[] bytes = new byte[byteValues.length];

    for (int i=0, len=bytes.length; i<len; i++) {
        bytes[i] = Byte.parseByte(byteValues[i].trim());
    }

    String str = new String(bytes);
    return str.toLowerCase();
}

1

base64 인코딩은 안전하고 "올바른 대답"을 주장 할 수는 있지만 Java 바이트 배열을 Java String으로 /있는 그대로 변환하는 방법을 찾고 있습니다. 즉, 바이트 배열의 각 멤버는 인코딩 / 전송에 추가 공간이 필요하지 않고 String 대응 부분에 그대로 남아 있습니다.

8 비트 투명 인코딩을 설명하는 이 답변 은 매우 도움이되었습니다. 나는 ISO-8859-1base64 인코딩에 필요한 팽창 된 공간 요구없이 테라 바이트의 이진 데이터를 사용 하여 성공적으로 앞뒤로 변환 (이진 <-> 문자열)하기 때문에 사용 사례 인 YMMV에 안전합니다.

또한 실험해야 할시기와 설명에 도움이되었습니다 .


0
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;    

private static String base64Encode(byte[] bytes)
{
    return new BASE64Encoder().encode(bytes);
}

private static byte[] base64Decode(String s) throws IOException
{
    return new BASE64Decoder().decodeBuffer(s);
}

왜? 바이트를 문자열로 변환하기 위해 Base64를 통과하는 이유는 무엇입니까? 오버 헤드.
james.garriss

0

작동 코드입니다.

            // Encode byte array into string . TemplateBuffer1 is my bytearry variable.

        String finger_buffer = Base64.encodeToString(templateBuffer1, Base64.DEFAULT);
        Log.d(TAG, "Captured biometric device->" + finger_buffer);


        // Decode String into Byte Array. decodedString is my bytearray[] 
        decodedString = Base64.decode(finger_buffer, Base64.DEFAULT);

-1

두 변환 모두에서 8 비트 문자 집합을 지정하십시오. 예를 들어 ISO-8859-1.


-1

String사용 에서 바이트를 읽고 바이트 데이터를 문자열로 변환하는 바이트 스트림 대신 문자 스트림으로 ByteArrayInputStream랩핑하십시오 BufferedReader.

package com.cs.sajal;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

public class TestCls {

    public static void main(String[] args) {

        String s=new String("Sajal is  a good boy");

        try
        {
        ByteArrayInputStream bis;
        bis=new ByteArrayInputStream(s.getBytes("UTF-8"));

        BufferedReader br=new BufferedReader(new InputStreamReader(bis));
        System.out.println(br.readLine());

        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

    }
}

출력은 다음과 같습니다

Sajal은 좋은 소년입니다


-1

간단한 for 루프를 사용하여 변환 할 수 있습니다.

public void byteArrToString(){
   byte[] b = {'a','b','$'};
   String str = ""; 
   for(int i=0; i<b.length; i++){
       char c = (char) b[i];
       str+=c;
   }
   System.out.println(str);
}


-3

문자열은 char (16 비트 부호없는)의 모음입니다. 따라서 음수를 문자열로 변환하면 번역에서 손실됩니다.


1
-1 : 올바르지 않습니다. 'byte'는 Java에서 부호있는 유형이지만 문자 세트 인코딩 및 디코딩을 수행하는 라이브러리 코드에 의해 부호없는 것으로 처리됩니다.
Stephen C

부호없는 8 비트 데이터 유형을 갖는 것이 실제로 언어에있는 것이 좋습니다. 불필요한 혼란을 피하십시오; ^)
Toad

Java 문자는 16 비트 일 것이라고 가정하십시오. Java의 UTF-16으로 인해 최대 32 비트로 확장 될 수 있습니다.
Joe Plante

1
@Toad는 실제로 그렇습니다. UTF-16으로 저장 될 때 일부 유니 코드 문자는 두 개의 코드 포인트, 즉 32 비트를 차지합니다. UTF-8에서도 마찬가지입니다. 일부 문자는 2/3/3 코드 포인트, 즉 16/24/32 비트를 사용합니다. 사실, UTF는 정확히 UTF에 관한 것입니다 (즉, UTF! = 유니 코드).
CAFxX

1
@Toad는 첫 번째 대리자를 얻습니다. 즉 캐릭터의 첫 번째 "반"만 나타납니다. String.charAt 메소드 및 Character 클래스 에 대한 문서를보십시오 .
CAFxX

-3
public class byteString {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        String msg = "Hello";
        byte[] buff = new byte[1024];
        buff = msg.getBytes("UTF-8");
        System.out.println(buff);
        String m = new String(buff);
        System.out.println(m);


    }

}

CharByte Encoding을 인자로 전달
Shyam Sreenivasan

1
코드 외에도 설명과 함께이 답변을 구체화하는 것이 좋습니다.
찰리 슐 리서

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.