Nasıl bayt dizisi dize ve tersi dönüştürmek için?


248

Android'de dizeye bir bayt dizisi dönüştürmek zorunda, ancak benim bayt dizisi negatif değerler içeriyor.

Bu dizeyi tekrar bayt dizisine dönüştürürsem, aldığım değerler orijinal bayt dizisi değerlerinden farklı olur.

Doğru dönüşümü elde etmek için ne yapabilirim? Dönüşüm yapmak için kullanıyorum kodu aşağıdaki gibidir:

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

Bu problemde sıkıştım.


3
Neden rasgele ikili verileri ilk olarak bir String'e dönüştürmeye çalışıyorsunuz? Cevapların zaten bahsettiği tüm karakter sorunları dışında, bunu yaparsanız String'i kötüye kullandığınız gerçeği de vardır. byte[]İkili verileriniz ve Stringmetniniz için a kullanmanın yanlışlığı nedir ?
Joachim Sauer

8
@ Joachim - bazen mağaza dizeleri gibi şeyler yapabilen harici araçlarınız vardır. Bu durumda bir bayt dizisini (bir şekilde kodlanmış) dizeye dönüştürebilirsiniz.
James Moore

Yanıtlar:


377

Bayt dizinizde bazı kodlamalar olmalıdır. Negatif değerleriniz varsa kodlama ASCII olamaz. Bunu anladıktan sonra, aşağıdakileri kullanarak bir bayt kümesini bir Dizeye dönüştürebilirsiniz:

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

Kullanabileceğiniz bir sürü kodlama vardır, Sun javadocs'taki Charset sınıfına bakın .


4
@MauricePerry neden işe yaramayacağını açıklayabilir misiniz UTF-8?
Asif Mushtaq

12
@UnKnown çünkü UTF-8 bazı karakterleri 2 veya 3 baytlık dizeler olarak kodlar. Her bayt dizisi geçerli bir UTF-8 kodlu dize değildir. ISO-8859-1 daha iyi bir seçim olacaktır: burada her karakter bir bayt olarak kodlanır.
Maurice Perry

1
Bu işe yarayabilir, ancak ne pahasına olursa olsun String yapıcısı kullanmaktan kaçınmalısınız.
hfontanez

bir bayt bir karaktere (8859-1 ile) ve istisna işleme (nio.charset ile) eşlemek için:String str = new String(bytes, java.nio.charset.StandardCharsets.ISO_8859_1);
iman

1
Java 1.7 beri, yeni dize (bayt, StandardCharsets.UTF_8) kullanabilir
ihebiheb

101

Arasında "uygun dönüşüm" byte[]ve Stringaçıkça size kullanım istediğiniz kodlama belirtmektir. Eğer bir ile başlarsanız byte[]ve aslında metin veri içeren değil, orada hayır "doğru dönüşüm". Strings metin içindir, byte[]ikili veri içindir ve yapılacak tek şey mantıklı olmadıkça, bunlar arasında dönüştürme yapmaktan kaçınmaktır .

Gerçekten bir Stringikili veri tutmak için bir kullanmanız gerekiyorsa, o zaman en güvenli yolu Base64 kodlaması kullanmaktır .


1
Evet, karakter kodlaması, dizeler ve baytlar arasında dönüştürme yapmak için bilmeniz gereken bir şeydir .
Raedwald

4
Base64 ve sen hayatımı kurtardın
mstzn

2
Base64 kodlaması sorunumu çözdü. UTF-8 tüm girdiler için çalışmadı
Al-Alamin

37

Kök sorunu (bence) bilmeden hangi için bir karakter kümesi kullanarak olmasıdır:

 bytes != encode(decode(bytes))

bazı durumlarda. UTF-8 böyle bir karakter setine bir örnektir. Özellikle, belirli bayt dizileri UTF-8'de geçerli kodlamalar değildir. UTF-8 kod çözücü bu sekanslardan biriyle karşılaşırsa, rahatsız edici baytları atmak veya "böyle bir karakter yok" için Unicode kod noktası olarak kodunu çözmekle yükümlüdür. Doğal olarak, karakterleri bayt olarak kodlamaya çalıştığınızda sonuç farklı olacaktır.

Çözüm şudur:

  1. Kullandığınız karakter kodlaması konusunda açık olun; yani String.toByteArrayaçık karakter kümesiyle bir String yapıcısı ve yöntemi kullanın .
  2. Bayt verileriniz için doğru karakter kümesini kullanın ... veya alternatif olarak (tüm bayt dizilerinin geçerli Unicode karakterlerle eşleştiği "Latin-1" gibi) kullanın.
  3. Baytlarınız (gerçekten) ikili veriler ise ve bunları "metin tabanlı" bir kanal üzerinden iletmek / almak istiyorsanız, bu amaç için tasarlanmış Base64 kodlaması gibi bir şey kullanın .

1
"Latin-1" kodlamasını kullandığınız için teşekkür ederiz!
Gonzo

31

Sadece Stringşu diziyle yeni bir yapı oluşturmamız gerekiyor : http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/

String s = new String(bytes);

Elde edilen dizenin baytları, kullandığınız karakter kümesine bağlı olarak değişir. Dize'yi çağırdığınızda yeni Dize (bayt) ve yeni Dize (bayt, Charset.forName ("utf-8")) ve yeni Dize (bayt, Charset.forName ("utf-16")) farklı bayt dizileri içerir. getBytes () (varsayılan karakter kümesine bağlı olarak)


9
Hayır. Ortaya çıkan dizenin baytları, kullandığınız karakter kümesine bağlı olarak değişir. new String(bytes)ve new String(bytes, Charset.forName("utf-8"))ve new String(bytes, Charset.forName("utf-16"))Aradığınızda tüm farklı bayt dizileri sahip olacaktır String#getBytes()(varsayılan karakter kümesi bağlı olarak)
NS du Toit

1
Yanıltıcı. Elde edilen chars'nin (ve dolayısıyla görüntülenen metnin) Stringkodu çözülürken bytesfarklıdır. Varsayılan kodlamayı kullanarak baytlara dönüştürme ( String#getBytes("charset")aksi halde belirtmek için kullanın ), farklı girdiyi dönüştürdüğü için mutlaka farklılık gösterir. Dizeler byte[]yapıldıklarını saklamazlar, charkodlamaları yoktur ve Stringaksi halde saklamazlar.
16:39

14

Kullanılması new String(byOriginal)ve geri dönüştürme byte[]kullanarak getBytes()iki garanti etmez byte[]eşit değerlerle. Bunun nedeni bir çağrı etmektir StringCoding.encode(..)kodlar hangi Stringiçin Charset.defaultCharset(). Bu kodlama sırasında, kodlayıcı bilinmeyen karakterleri değiştirmeyi ve başka değişiklikler yapmayı seçebilir. Bu nedenle, String.getBytes()başlangıçta yapıcıya geçtiğiniz için kullanmak eşit bir dizi döndürmeyebilir.


9

Sorun neden : Birisi önceden belirtildiği gibi: Bir bayt [] ile başlıyorsanız ve aslında metin verisi içermiyorsa, "uygun dönüşüm" yoktur. Dizeler metin içindir, byte [] ikili veriler içindir ve yapmanız gereken tek şey, kesinlikle gerekmedikçe aralarında dönüştürme yapmaktan kaçınmaktır.

Ben bir pdf dosyasından byte [] oluşturmaya çalıştıktan sonra Dize dönüştürmek ve sonra Dize giriş olarak alarak ve dosyaya geri dönüştürme çalışırken bu sorunu gözlemliyordum.

Kodlama ve kod çözme mantığınızın benim yaptığımla aynı olduğundan emin olun. Bayt [] 'ı açıkça Base64'e kodladım ve dosyayı yeniden oluşturmak için kodunu çözdüm.

Kullanım durum: nedeniyle bazı sınırlama ben gönderilenle çalışıyordu byte[]içinde request(POST)ve süreç aşağıdaki gibidir:

PDF Dosyası >> Base64.encodeBase64 (bayt []) >> Dize >> İstekte gönder (POST) >> alma Dize >> Base64.decodeBase64 (bayt []) >> ikili oluştur

Bunu deneyin ve bu benim için çalıştı.

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

Bu benim için iyi çalışıyor:

String cd="Holding some value";

Dizeden bayta [] dönüştürme:

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

Bayt [] biçiminden dizeye dönüştürülüyor:

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
Bu soruya cevap vermiyor.
james.garriss

Soruya cevap vermiyor ama faydalı oldu +1
Lazy Ninja

5

Cevapların hiçbirinde olmayan bir şey fark ettim. Bayt dizisindeki her baytı karakterlere atabilir ve bir char dizisine koyabilirsiniz. Sonra dize

new String(cbuf)
burada cbuf char dizisidir. Geri dönüştürmek için, karakterlerin her birini bir bayt dizisine koymak üzere baytlara döküm dizesinde döngü yapın ve bu bayt dizisi birincisi ile aynı olacaktır.


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 yapmalı:

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

2

Bir bayt dizisini bir dizeye dönüştüren birkaç yöntem vardır. İyi çalıştıklarını test ettim.

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

Buna rağmen

new String(bytes, "UTF-8")

doğru olduğunu UnsupportedEncodingExceptionkontrol eder bir istisna ile başa çıkmak için zorlar. Bir bayt dizisini aşağıdakine dönüştürmek için Java 1.6'dan beri başka bir kurucu olarak kullanabilirsiniz String:

new String(bytes, StandardCharsets.UTF_8)

Bu herhangi bir istisna oluşturmaz.

Geri dönüştürme ayrıca şu şekilde yapılmalıdır StandardCharsets.UTF_8:

"test".getBytes(StandardCharsets.UTF_8)

Yine, kontrol edilen istisnalarla uğraşmaktan kaçının.


1

Bu yöntemle bir dizeye bayt dizisi dönüştürme başarılı:

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 kodlaması güvenli ve bir "doğru cevap" tartışabilirken, ben buraya geldi gibi bir Java String dizi / Java Dizesi dönüştürmek için bir yol arıyor. Diğer bir deyişle, bayt dizisinin her bir üyesi, Dize karşılıklarında bozulmadan kalır ve kodlama / taşıma için fazladan boşluk gerekmez.

8 bit şeffaf kodlamaları açıklayan bu cevap benim için çok yararlı oldu. kullandımISO-8859-1 YMMV - yani benim bir kullanım örneği için güvenlidir, base64 kodlama için gerekli şişirilmiş uzay gereksinimleri olmadan - başarıyla ileri geri (Dize <> ikili) dönüştürmek için ikili terabyte veri üzerinde.

Bu, ne zaman denemeniz gerektiğini / denemeniz gerektiğini açıklamada da yardımcı oldu.


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

Neden? Neden bir baytı bir String'e dönüştürmek için Base64'e gidelim? Tepegöz.
james.garriss

0

İşte çalışma kodu.

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

Her iki dönüşümde de 8 bitlik bir karakter kümesi belirtmeyi deneyin. Örneğin ISO-8859-1.


-1

Dan bayt oku Stringkullanarak ByteArrayInputStreamve ile sarın BufferedReaderhangi Char Akış yerine String bayt veri dönüştürür Byte Akışınızdır.

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

    }
}

Çıktı:

Sajal olur bir iyi çocuk


-1

Dönüşüm için döngü için basit kullanabilirsiniz:

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

Dize, char'ların bir koleksiyonudur (16bit imzasız). Dolayısıyla, negatif sayıları bir dizeye dönüştürecekseniz, çeviride kaybolurlar.


1
-1: Bu yanlış. 'Bayt' Java'da imzalı bir türken, karakter kümesi kodlama ve kod çözme yapan kitaplık kodunun imzasız olduğu kabul edilir.
Stephen C

İmzasız bir 8 bit veri tipine sahip olmanın neden bir dilde olması iyi bir fikirdir. Gereksiz karışıklığı önler; ^)
Kurbağa

Bir Java karakterinin 16 bit olacağını varsaymaya dikkat edin, Java'nın UTF-16'sı nedeniyle 32 bite kadar genişleyebilirler
Joe Plante

1
@ Evet, evet, UTF-16 olarak saklandığında bazı Unicode karakterler iki kod noktası, yani 32 bit alır. Aynı şey UTF-8'de de olur: bazı karakterler iki / üç / dört kod noktası kullanır, yani 16/24/32 bit. Aslında, UTF tam olarak budur (yani UTF! = Unicode).
CAFxX

1
@Taket ilk vekili alırsınız - yani karakterin sadece ilk "yarısı". String.charAt yöntemi ve Character sınıfı için docs'a bakın .
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);


    }

}

GetBytes
Shyam Sreenivasan

1
Bu yanıta koda ek olarak bir açıklama eklemeyi düşünebilirsiniz.
Charlie Schliesser

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.