Bayt dizisini String'e (Java) dönüştürme


85

Google app Engine'de bir web uygulaması yazıyorum. İnsanların .htmlblobstore'da bir dosya olarak saklanan html kodunu düzenlemelerine olanak tanır .

Dosyadaki byte[]tüm karakterlerden bir döndürmek için fetchData kullanıyorum . Kullanıcının html kodunu düzenlemesi için bir html'ye yazdırmaya çalışıyorum. Her şey harika çalışıyor!

Şu andaki tek sorunum şu:

Bayt dizisi bir dizeye geri dönüştürülürken bazı sorunlar yaşıyor. Akıllı alıntılar ve birkaç karakter korkak görünüyor. (? 'ler veya Japonca semboller vb.) Özellikle soruna neden olan negatif değerlere sahip olan birkaç bayt.

Akıllı tırnaklar olarak geri geliyor -108ve -109bayt dizide. Bu neden ve doğru karakter kodlamasını göstermek için negatif baytların kodunu nasıl çözebilirim?



Merhaba, bunun gerçekten eski bir gönderi olduğunu biliyorum ama benzer sorunlarla karşılaşıyorum. SSL için ortadaki adam vekili yapıyorum. Karşılaştığım sorun seninkiyle aynı. Soketi dinliyorum ve verileri içeri InputStreamve sonra içine alıyorum byte[]. Şimdi bunu String'e dönüştürmeye çalıştığımda byte[](saldırılar için yanıt gövdesini kullanmam gerekiyor), akıllı alıntılarla ve soru işaretleriyle ve ne yapmayla dolu gerçekten komik karakterler alıyorum. Ben senin sorun biz de ilgileniyor olarak benimkiyle aynı olduğuna inanıyoruz htmliçinde byte[]. Lütfen tavsiye verir misiniz?
Parul S

Bu arada, sistemimin kodlamasını Sytem.properties kullanarak bulacak kadar gittim ve "Cp1252" olduğunu buldum. Şimdi kullandım String str=new String(buffer, "Cp1252");ama yardım etmedim .
Parul S

Yanıtlar:


141

Bayt dizisi, özel bir kodlamadaki (bilmeniz gereken) karakterler içerir. Onu bir String'e dönüştürmenin yolu:

String decoded = new String(bytes, "UTF-8");  // example for one encoding type

Yolla - ham baytlar, java veri türü byteimzalandığı için negatif ondalık sayılar olarak görünebilir , -128 ila 127 aralığını kapsar.


-109 = 0x93: Control Code "Set Transmit State"

(-109) değeri, UNICODE'da yazdırılamayan bir kontrol karakteridir. Dolayısıyla, UTF-8 bu karakter akışı için doğru kodlama değildir.

0x93"Windows-1252" de aradığınız "akıllı alıntı" olduğundan, bu kodlamanın Java adı "Cp1252" dir. Sonraki satır bir test kodu sağlar:

System.out.println(new String(new byte[]{-109}, "Cp1252")); 

5
UTF-8 kullanmayı denedim ve hala? 'S olarak çıktı. Neden bu negatif değerler için bir eşleme bulamıyor?
Josh

0x93, UTF-8'de geçerli bir devam baytıdır - bu baytın varlığı, ilk iki bit kümesiyle bir bayttan sonra gelmezse yalnızca UTF-8 olmasını engeller.
Nick Johnson

1
@Josh Andreas nedenini açıklıyor - çünkü Java'nın byteveri türü imzalanmış. "Negatif" değerler yalnızca en önemli bayt kümesine sahip baytlardır. Ayrıca, kullanmanız gereken en olası karakter kümesinin ne olduğunu da açıklıyor - Windows-1252. Bununla birlikte, tahmin etmek zorunda kalmadan bağlam veya kurallardan hangi karakter kümesini kullanacağınızı bilmelisiniz.
Nick Johnson

25

Java 7 ve üstü

İstediğiniz kodlamayı StandardCharsets'tenString bir Charsetsabit olarak yapıcıya da iletebilirsiniz . Bu , diğer cevaplarda önerildiği gibi, kodlamayı a olarak geçirmekten daha güvenli olabilir .String

Örneğin, UTF-8 kodlaması için

String bytesAsString = new String(bytes, StandardCharsets.UTF_8);

1
Bu, 2011'deki bir cevabın tekrarı. -1
james.garriss

2
@ james.garriss Sadece java 7'de tanıtılan kodlamanın bir sabit olarak geçirilmesine izin veren yeni bir kurucudan bahsettiğim için öyle olduğunu sanmıyorum, bu benim görüşüme göre önceki api'den daha güzel ve daha güvenli kodlamanın bir String olarak geçtiği önceki cevaplarda bahsediliyordu.
davnicwil


5
public class Main {

    /**
     * Example method for converting a byte to a String.
     */
    public void convertByteToString() {

        byte b = 65;

        //Using the static toString method of the Byte class
        System.out.println(Byte.toString(b));

        //Using simple concatenation with an empty String
        System.out.println(b + "");

        //Creating a byte array and passing it to the String constructor
        System.out.println(new String(new byte[] {b}));

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Main().convertByteToString();
    }
}

Çıktı

65
65
A

5
public static String readFile(String fn)   throws IOException 
{
    File f = new File(fn);

    byte[] buffer = new byte[(int)f.length()];
    FileInputStream is = new FileInputStream(fn);
    is.read(buffer);
    is.close();

    return  new String(buffer, "UTF-8"); // use desired encoding
}

3
Bu kod, readbir istisna atarsa ​​bir kaynağı sızdırır .
Raedwald

4

öneririm Arrays.toString(byte_array);

Amacınıza bağlıdır. Örneğin, hata ayıklama sırasında görebileceğiniz format gibi bir bayt dizisini kaydetmek istedim, bu şuna benzer: [1, 2, 3]Baytları karakter biçimine dönüştürmeden tam olarak aynı değeri kaydetmek istiyorsanız, Arrays.toString (byte_array)bunu yapar. Ancak bayt yerine karakter kaydetmek istiyorsanız, kullanmalısınız String s = new String(byte_array). Bu durumda, karakter formatındaki seşdeğerine eşittir [1, 2, 3].


Bunu neden önerdiğiniz konusunda daha fazla bilgi verebilir misiniz? (Sorunu çözecek mi? Neden çözdüğünü söyleyebilir misiniz?) Teşekkürler!
Dean J

Amacınıza bağlıdır. Örneğin, hata ayıklama sırasında görebileceğiniz format gibi bir bayt dizisini kaydetmek istedim, bu şuna benzer: [1, 2, 3] Baytları karakter biçimine dönüştürmeden tam olarak aynı değeri kaydetmek istiyorsanız, Arrays.toString (byte_array) bunu yapar. Ancak, bayt yerine karakterleri kaydetmek istiyorsanız, String s = new String (byte_array) kullanmanız gerekir. Bu durumda, s, karakter formatında [1, 2, 3] 'e eşittir.
Soru

@sas, bu bilgiyi yorum yerine (düzenleyerek) cevabınızın kendisine eklemelisiniz. Genel olarak, SO'da, yorumların herhangi bir noktada silinebileceğini her zaman aklınızda bulundurmalısınız - gerçekten önemli bilgiler yanıtın kendisinde olmalıdır.
Jeen Broekstra

3

Andreas_D'nin bir önceki cevabı güzel. Çıktıyı görüntülediğiniz her yerde bir yazı tipi ve bir karakter kodlaması olacağını ve bazı karakterleri desteklemeyebileceğini ekleyeceğim.

Sorunun Java mı yoksa ekranınız mı olduğunu anlamak için şunu yapın:

    for(int i=0;i<str.length();i++) {
        char ch = str.charAt(i);
        System.out.println(i+" : "+ch+" "+Integer.toHexString(ch)+((ch=='\ufffd') ? " Unknown character" : ""));
    }

Java, anlayamadığı tüm karakterleri bilinmeyen karakterler için resmi karakter olan 0xfffd ile eşleştirmiş olacaktır. Bir '?' çıktıda, ancak 0xfffd ile eşlenmemişse, sorun Java değil ekran yazı tipiniz veya kodlamanızdır.

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.