Bagaimana cara mengubah byte array ke string dan sebaliknya?


247

Saya harus mengubah array byte ke string di Android, tetapi array byte saya mengandung nilai negatif.

Jika saya mengonversi string itu lagi ke byte array, nilai yang saya dapatkan berbeda dari nilai array byte asli.

Apa yang bisa saya lakukan untuk mendapatkan konversi yang tepat? Kode yang saya gunakan untuk melakukan konversi adalah sebagai berikut:

// 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);

Saya terjebak dalam masalah ini.


3
Mengapa Anda mencoba mengonversi data biner sewenang-wenang menjadi sebuah String? Terlepas dari semua masalah charset jawaban yang sudah disebutkan, ada juga fakta bahwa Anda menyalahgunakan String jika Anda melakukan ini. Apa yang salah dengan menggunakan byte[]untuk data biner Anda dan Stringuntuk teks Anda?
Joachim Sauer

8
@ Joachim - kadang-kadang Anda memiliki alat eksternal yang dapat melakukan hal-hal seperti string toko. Anda ingin dapat mengubah array byte menjadi string (dikodekan dalam beberapa cara) dalam kasus itu.
James Moore

Jawaban:


377

Array byte Anda harus memiliki beberapa penyandian. Pengkodean tidak bisa ASCII jika Anda memiliki nilai negatif. Setelah Anda mengetahuinya, Anda dapat mengonversi satu set byte ke sebuah String menggunakan:

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

Ada sekelompok pengkodean dapat Anda gunakan, lihat di kelas Charset di javadocs Sun .


4
@MauricePerry dapatkah Anda menjelaskan mengapa itu tidak berhasil UTF-8?
Asif Mushtaq

12
@UnKnown karena UTF-8 mengkodekan beberapa karakter sebagai string 2- atau 3- byte. Tidak setiap byte array adalah string UTF-8-encoded yang valid. ISO-8859-1 akan menjadi pilihan yang lebih baik: di sini setiap karakter dikodekan sebagai byte.
Maurice Perry

1
Ini mungkin berhasil, tetapi Anda harus menghindari menggunakan konstruktor String di semua biaya.
hfontanez

untuk memetakan satu byte ke satu char (dengan 8859-1) dan tidak terkecuali penanganan (dengan nio.charset):String str = new String(bytes, java.nio.charset.StandardCharsets.ISO_8859_1);
iman

1
sejak Java 1.7, Anda dapat menggunakan String baru (byte, StandardCharsets.UTF_8)
ihebiheb

101

"Konversi yang tepat" antara byte[]dan Stringuntuk secara eksplisit menyatakan penyandian yang ingin Anda gunakan. Jika Anda mulai dengan a byte[]dan sebenarnya tidak berisi data teks, tidak ada "konversi yang tepat". StringIni untuk teks, byte[]untuk data biner, dan satu-satunya hal yang benar-benar masuk akal untuk dilakukan adalah menghindari konversi di antara mereka kecuali Anda benar-benar harus melakukannya.

Jika Anda benar-benar harus menggunakan a Stringuntuk menyimpan data biner maka cara paling aman adalah menggunakan pengkodean Base64 .


1
Ya, pengkodean karakter adalah sesuatu yang harus Anda ketahui untuk mengkonversi antara string dan byte.
Raedwald

4
Base64 dan kamu menyelamatkan hidupku
mstzn

2
Pengkodean Base64 memecahkan masalah saya. UTF-8 tidak bekerja untuk semua input
Al-Alamin

37

Masalah root adalah (saya pikir) bahwa Anda tanpa disadari menggunakan set karakter yang:

 bytes != encode(decode(bytes))

dalam beberapa kasus. UTF-8 adalah contoh dari set karakter tersebut. Secara khusus, urutan byte tertentu bukan penyandian yang valid di UTF-8. Jika dekoder UTF-8 menemukan salah satu dari sekuens ini, Anda dapat membuang byte yang menyinggung atau mendekodekannya sebagai titik kode Unicode untuk "no character like". Tentu saja, ketika Anda kemudian mencoba untuk menyandikan karakter sebagai byte, hasilnya akan berbeda.

Solusinya adalah:

  1. Secara eksplisit tentang pengkodean karakter yang Anda gunakan; yaitu menggunakan konstruktor dan String.toByteArraymetode String dengan charset eksplisit.
  2. Gunakan set karakter yang tepat untuk data byte Anda ... atau sebagai alternatif (seperti "Latin-1" di mana semua urutan byte memetakan ke karakter Unicode yang valid.
  3. Jika byte Anda (benar-benar) data biner dan Anda ingin dapat mengirim / menerimanya melalui saluran "berbasis teks", gunakan sesuatu seperti pengkodean Base64 ... yang dirancang untuk tujuan ini .

1
Terima kasih atas tip menggunakan penyandian "Latin-1"!
Gonzo

31

Kita hanya perlu membuat yang baru Stringdengan array: http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/

String s = new String(bytes);

Bytes dari string yang dihasilkan berbeda tergantung pada charset apa yang Anda gunakan. String baru (byte) dan String baru (byte, Charset.forName ("utf-8")) dan String baru (byte, Charset.forName ("utf-16")) semua akan memiliki array byte yang berbeda ketika Anda memanggil String # getBytes () (tergantung pada rangkaian karakter default)


9
Tidak. Bytes dari string yang dihasilkan berbeda tergantung pada charset apa yang Anda gunakan. new String(bytes)dan new String(bytes, Charset.forName("utf-8"))dan new String(bytes, Charset.forName("utf-16"))semua akan memiliki array byte yang berbeda saat Anda menelepon String#getBytes()(tergantung pada charset default)
NS du Toit

1
Menyesatkan. The chars (dan dengan demikian teks ditampilkan) dari yang dihasilkan Stringberbeda ketika decoding bytesberbeda. Konversi kembali ke byte menggunakan pengkodean default (gunakan String#getBytes("charset")untuk menentukan lain) tentu akan berbeda karena mengkonversi input yang berbeda. String tidak menyimpan dari mana byte[]mereka dibuat, chars tidak memiliki encoding dan Stringtidak menyimpannya sebaliknya.
zapl

14

Menggunakan new String(byOriginal)dan mengonversi kembali ke byte[]menggunakan getBytes()tidak menjamin dua byte[]dengan nilai yang sama. Ini karena panggilan StringCoding.encode(..)yang akan mengkodekan Stringke Charset.defaultCharset(). Selama penyandian ini, penyandi mungkin memilih untuk mengganti karakter yang tidak dikenal dan melakukan perubahan lainnya. Oleh karena itu, menggunakan String.getBytes()mungkin tidak mengembalikan array yang sama seperti Anda awalnya telah diteruskan ke konstruktor.


9

Mengapa masalahnya: Seperti seseorang telah ditentukan: Jika Anda mulai dengan byte [] dan itu sebenarnya tidak berisi data teks, tidak ada "konversi yang tepat". String adalah untuk teks, byte [] adalah untuk data biner, dan satu-satunya hal yang benar-benar masuk akal untuk dilakukan adalah menghindari konversi di antara mereka kecuali Anda benar-benar harus melakukannya.

Saya mengamati masalah ini ketika saya mencoba membuat byte [] dari file pdf dan kemudian mengubahnya menjadi String dan kemudian mengambil String sebagai input dan mengkonversi kembali ke file.

Jadi pastikan logika encoding dan decoding Anda sama dengan yang saya lakukan. Saya secara eksplisit menyandikan byte [] ke Base64 dan mendekodekannya untuk membuat file lagi.

Gunakan-kasus: Karena beberapa keterbatasan saya mencoba untuk pengirimannya byte[]di request(POST)dan proses adalah sebagai berikut:

File PDF >> Base64.encodeBase64 (byte []) >> String >> Kirim dalam permintaan (POST) >> menerima String >> Base64.decodeBase64 (byte []) >> buat biner

Coba ini dan ini berhasil untuk saya ..

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

Ini berfungsi baik untuk saya:

String cd="Holding some value";

Mengonversi dari string ke byte []:

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

Konversi dari byte [] ke string:

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

Ini tidak menjawab pertanyaan.
james.garriss

Tidak menjawab pertanyaan tetapi bermanfaat +1
Lazy Ninja

5

Saya memang memperhatikan sesuatu yang tidak ada dalam jawaban. Anda bisa melemparkan setiap byte dalam array byte ke karakter, dan menempatkannya dalam array char. Maka talinya adalah

new String(cbuf)
di mana cbuf adalah array char. Untuk mengkonversi kembali, loop melalui string casting masing-masing karakter ke byte untuk dimasukkan ke dalam array byte, dan array byte ini akan sama dengan yang pertama.


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 harus melakukannya:

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

2

Berikut adalah beberapa metode yang mengubah array byte ke string. Saya sudah menguji mereka mereka bekerja dengan baik.

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

Meskipun

new String(bytes, "UTF-8")

benar itu melempar UnsupportedEncodingExceptionyang memaksa Anda untuk berurusan dengan pengecualian yang diperiksa. Anda dapat menggunakan sebagai alternatif konstruktor lain sejak Java 1.6 untuk mengubah array byte menjadi String:

new String(bytes, StandardCharsets.UTF_8)

Yang ini tidak membuang pengecualian.

Konversi kembali juga harus dilakukan dengan StandardCharsets.UTF_8:

"test".getBytes(StandardCharsets.UTF_8)

Sekali lagi Anda menghindari berurusan dengan pengecualian diperiksa.


1

Saya berhasil mengubah byte array ke string dengan metode ini:

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

Sementara pengkodean base64 aman dan orang bisa berpendapat "jawaban yang tepat", saya tiba di sini mencari cara untuk mengkonversi array byte Java ke / dari Java String apa adanya. Yaitu, di mana setiap anggota array byte tetap utuh dalam rekan String-nya, tanpa ruang tambahan yang diperlukan untuk pengkodean / transportasi.

Jawaban ini menggambarkan penyandian transparan 8bit sangat membantu bagi saya. Saya menggunakan ISO-8859-1terabyte data biner untuk mengkonversi bolak-balik dengan sukses (binary <-> String) tanpa persyaratan ruang yang diperlukan untuk pengkodean base64, jadi aman untuk kasus penggunaan saya - YMMV.

Ini juga membantu dalam menjelaskan kapan / jika Anda harus bereksperimen.


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

Mengapa? Mengapa harus melalui Base64 untuk mengubah byte ke String? Overhead.
james.garriss

0

Di sini kode kerjanya.

            // 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

Baca byte dari Stringmenggunakan ByteArrayInputStreamdan bungkus dengan BufferedReaderyang Stream Char bukan Byte Stream yang mengubah data byte ke String.

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

    }
}

Output adalah:

Sajal adalah anak yang baik


-1

Anda dapat menggunakan simpel untuk loop untuk konversi:

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

String adalah koleksi char (16bit unsigned). Jadi, jika Anda akan mengubah angka negatif menjadi string, mereka akan hilang dalam terjemahan.


1
-1: Ini salah. Walaupun 'byte' adalah tipe yang ditandatangani di Java, mereka diperlakukan sebagai tidak ditandai oleh kode pustaka yang melakukan pengodean dan dekode karakter.
Stephen C

Sebuah contoh bagus mengapa memiliki datatype 8 bit yang tidak ditandatangani benar-benar ide yang baik untuk dimiliki dalam suatu bahasa. Hindari kebingungan yang tidak perlu; ^)
Toad

Berhati-hatilah dengan asumsi bahwa char Java akan menjadi 16 bit, karena UTF-16 Java, mereka dapat berkembang hingga 32 bit
Joe Plante

1
@ Memuat sebenarnya ya, beberapa karakter Unicode saat disimpan sebagai UTF-16 mengambil dua titik kode, yaitu 32 bit. Hal yang sama terjadi pada UTF-8: beberapa karakter menggunakan dua / tiga / empat titik kode, yaitu 16/24/32 bit. Sebenarnya, itulah yang menjadi tujuan UTF (yaitu UTF! = Unicode).
CAFxX

1
@ Memuat Anda akan mendapatkan pengganti pertama - yaitu hanya "setengah" pertama dari karakter. Lihatlah dokumen untuk metode String.charAt dan kelas Karakter .
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);


    }

}

Pass The Charset Encoding sebagai argumen untuk getBytes
Shyam Sreenivasan

1
Anda mungkin ingin mempertimbangkan menyempurnakan jawaban ini dengan penjelasan di samping kode.
Charlie Schliesser

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.