Java'da Dizeleri UTF8 bayt dizilerine dönüştürme


239

Java, ben bir String var ve bir bayt dizisi (UTF8 veya başka bir kodlama) olarak kodlamak istiyorum. Alternatif olarak, bir bayt dizisi (bazı bilinen kodlamada) var ve bir Java String dönüştürmek istiyorum. Bu dönüşümleri nasıl yaparım?

Yanıtlar:


355

Dönüştürmek Dize byte []:

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);

Dönüştürmek byte [] için Dize:

byte[] b = {(byte) 99, (byte)97, (byte)116};
String s = new String(b, StandardCharsets.US_ASCII);

Elbette doğru kodlama adını kullanmalısınız. Örneklerimde en yaygın iki kodlama olan US-ASCII ve UTF-8 kullanıldı.


30
US-ASCII aslında günümüzde çok yaygın bir kodlama değildir. Windows-1252 ve ISO-8859-1 (ASCII'nin üst kümeleri) çok daha yaygın.
Michael Borgwardt

11
Aslında bunu işimde oldukça yaygın buluyorum. Sıklıkla Windows-1252 veya ISO-8859-1 olarak kaydedilmiş veya "son 10 yıldır sahip olduğumuz eski programın çıktısı" olarak kaydedilmiş, ancak geçerli olduğu garanti edilen bayt içeren bayt akışlarını okuyorum. ABD-ASCII karakterleri. Ayrıca genellikle bu tür dosyaları oluşturmak için bir gereksinimim var (ASCII olmayan karakterleri işleyebilecek veya edemeyebilecek kodla tüketim için) Temel olarak, US-ASCII birçok yazılım parçasının "en büyük ortak paydası" dır.
mcherm

1
Ancak bu yöntem, dönüşümdeki herhangi bir sorunu bildirmez. İstediğiniz bu olabilir. Değilse, bunun yerine CharsetEncoder kullanılması önerilir.
Michael Piefel

7
@Pacerier çünkü Karakter Kümesi için dokümanlar standart karakter kümelerinden biri olarak "UTF-8" i listeliyor. Yazımınızın da kabul edildiğine inanıyorum, ancak belgelerin söylediklerine gittim.
mcherm

20
JDK7'den beri StandardCharsets.UTF_8'i kullanabilirsiniz docs.oracle.com/javase/7/docs/api/java/nio/charset/…
Rafael Membrives

95

Aşağıda, her dönüşüm için Karakter Kümesi araması yapmaktan kaçınan bir çözüm bulunmaktadır:

import java.nio.charset.Charset;

private final Charset UTF8_CHARSET = Charset.forName("UTF-8");

String decodeUTF8(byte[] bytes) {
    return new String(bytes, UTF8_CHARSET);
}

byte[] encodeUTF8(String string) {
    return string.getBytes(UTF8_CHARSET);
}

4
@mcherm: Performans farkı küçük olsa bile, mümkün olduğunda dize formları üzerinde nesneler (Charset, URL, vb.) kullanmayı tercih ederim.
Bart van Heukelom

7
Not: "Beri 1.6" genel Dize (bayt [] bayt, Charset karakter kümesi)
leo

1
"Her dönüşüm için Karakter Kümesi araması yapmaktan kaçınıyor" ile ilgili olarak ... lütfen kaynak belirtiniz. Java.nio.charset.Charset , String.getBytes üzerine kurulu değildir ve bu nedenle String.getBytes'ten daha fazla yüke sahip değildir?
Pacerier

2
Docs do state: "Bu karakter dizisi belirtilen karakter kümesinde kodlanamadığı zaman davranışı belirtilmemiş. Kodlama işlemi üzerinde daha fazla denetim gerektiğinde CharsetEncoder sınıfı kullanılmalıdır."
paiego

24
Not: Java 1.7'den beri StandardCharsets.UTF_8, UTF-8 karakter kümesine erişmenin sabit bir yolu için kullanabilirsiniz .
Kat

17
String original = "hello world";
byte[] utf8Bytes = original.getBytes("UTF-8");

Teşekkürler! Diğer dönüşüm yönünü ekleyerek tekrar yazdım.
mcherm

1
@ smink Kısa çizgi isteğe bağlı değil. Bu "UTF-8" kullanmalıdır
Mel Nicholson

14

Doğrudan String (byte [], String) yapıcısı ve getBytes (String) yöntemi ile dönüştürebilirsiniz. Java, kullanılabilir karakter kümelerini Charset sınıfı aracılığıyla gösterir . JDK belgeleri desteklenen kodlamaları listeler .

Zamanın% 90'ı, bu tür dönüşümler akışlarda gerçekleştirilir, bu nedenle Reader / Writer sınıflarını kullanırsınız. Rasgele bayt akışlarında String yöntemlerini kullanarak aşamalı olarak kod çözemezsiniz - kendinizi çok baytlı karakterleri içeren hatalara açık bırakırsınız.


Detaylandırabilir misin? Uygulamam Dizeleri kodlayıp çözerse UTF-8, çok baytlı karakterlerle ilgili kaygı nedir?
raffian

@raffian Tüm karakter verilerini tek seferde dönüştürmezseniz sorunlar oluşabilir. Bir örnek için buraya bakın .
McDowell

12

Tomcat7 uygulamam dizeleri ISO-8859-1 olarak kabul ediyor; HTTP isteğinin içerik türüne rağmen. 'É' gibi karakterleri doğru yorumlamaya çalışırken aşağıdaki çözüm benim için çalıştı.

byte[] b1 = szP1.getBytes("ISO-8859-1");
System.out.println(b1.toString());

String szUT8 = new String(b1, "UTF-8");
System.out.println(szUT8);

Dizeyi US-ASCII olarak yorumlamaya çalışırken bayt bilgisi doğru şekilde yorumlanmamıştır.

b1 = szP1.getBytes("US-ASCII");
System.out.println(b1.toString());

8
FYI, Java 7'den itibaren StandardCharSets.UTF_8ve gibi karakter kümesi adları için sabitleri kullanabilirsiniz StandardCharSets.ISO_8859_1.
Basil Bourque

Yukarıda belirtilen ilk çözüm için kesinlikle iyi çalışarak, benim gün kurtardı.
Hassan Jamil

7

Alternatif olarak Apache Commons'tan StringUtils kullanılabilir.

 byte[] bytes = {(byte) 1};
 String convertedString = StringUtils.newStringUtf8(bytes);

veya

 String myString = "example";
 byte[] convertedBytes = StringUtils.getBytesUtf8(myString);

Standart olmayan karakter kümeniz varsa, buna göre getBytesUnchecked () veya newString () öğesini kullanabilirsiniz .


4
Bu StringUtils Commons Langec değil, Commons Lang unutmayın.
Arend / Reinersdorff

Evet, biraz yakaladım! Gradle için Maven kullanıcıları: "commons-codec: commons-codec: 1.10" (yazma sırasında). Bu, örneğin Apache POI'ye bağımlılık olarak da gelir. Bunun dışında her zamanki gibi Apache Commons kurtarmak için!
mike kemirgen

2

Bir bayt dizisini normal bir dize mesajına çözmek için sonunda bu kodla UTF-8 kodlamasıyla çalıştım:

/* Convert a list of UTF-8 numbers to a normal String
 * Usefull for decoding a jms message that is delivered as a sequence of bytes instead of plain text
 */
public String convertUtf8NumbersToString(String[] numbers){
    int length = numbers.length;
    byte[] data = new byte[length];

    for(int i = 0; i< length; i++){
        data[i] = Byte.parseByte(numbers[i]);
    }
    return new String(data, Charset.forName("UTF-8"));
}

1

7 bit ASCII veya ISO-8859-1 (inanılmaz derecede yaygın bir biçim) kullanıyorsanız, yeni bir java.lang.String oluşturmanız gerekmez . Baytı char'a dökmek çok daha performanslıdır:

Tam çalışma örneği:

for (byte b : new byte[] { 43, 45, (byte) 215, (byte) 247 }) {
    char c = (char) b;
    System.out.print(c);
}

Eğer varsa değil kullanılarak genişletilmiş karakterleri Ş, Ç Æ, A, C, I, E gibi ve sadece iletilen değerler, ilk 128 Unicode karakter olduğundan emin olabilir o zaman bu kodu, ayrıca UTF-8 ve genişletilmiş ASCII için çalışma (cp-1252 gibi).


1

Yorum yapamıyorum ama yeni bir konu başlatmak istemiyorum. Ama bu işe yaramıyor. Basit bir gidiş dönüş:

byte[] b = new byte[]{ 0, 0, 0, -127 };  // 0x00000081
String s = new String(b,StandardCharsets.UTF_8); // UTF8 = 0x0000, 0x0000,  0x0000, 0xfffd
b = s.getBytes(StandardCharsets.UTF_8); // [0, 0, 0, -17, -65, -67] 0x000000efbfbd != 0x00000081

Ben b [] aynı dizi önce ve sonra değil kodlama gerekir (bu ilk cevaba atıfta bulunur).


0
//query is your json   

 DefaultHttpClient httpClient = new DefaultHttpClient();
 HttpPost postRequest = new HttpPost("http://my.site/test/v1/product/search?qy=");

 StringEntity input = new StringEntity(query, "UTF-8");
 input.setContentType("application/json");
 postRequest.setEntity(input);   
 HttpResponse response=response = httpClient.execute(postRequest);

String Entity, 'query' öğesini utf-8'e dönüştürüyor mu yoksa sadece varlığı eklerken hatırlıyor musunuz?
SyntaxRules

0
Charset UTF8_CHARSET = Charset.forName("UTF-8");
String strISO = "{\"name\":\"א\"}";
System.out.println(strISO);
byte[] b = strISO.getBytes();
for (byte c: b) {
    System.out.print("[" + c + "]");
}
String str = new String(b, UTF8_CHARSET);
System.out.println(str);

0
Reader reader = new BufferedReader(
    new InputStreamReader(
        new ByteArrayInputStream(
            string.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));

-9

çok geç ama ben sadece bu sorunla karşılaştı ve bu benim düzeltme:

private static String removeNonUtf8CompliantCharacters( final String inString ) {
    if (null == inString ) return null;
    byte[] byteArr = inString.getBytes();
    for ( int i=0; i < byteArr.length; i++ ) {
        byte ch= byteArr[i]; 
        // remove any characters outside the valid UTF-8 range as well as all control characters
        // except tabs and new lines
        if ( !( (ch > 31 && ch < 253 ) || ch == '\t' || ch == '\n' || ch == '\r') ) {
            byteArr[i]=' ';
        }
    }
    return new String( byteArr );
}

2
Birincisi, bu bir dönüşüm değil: yazdırılamayan baytların kaldırılması. İkincisi, temel OS'nin varsayılan kodlamasının yazdırılabilir karakterler için gerçekten ASCII'ye dayalı olduğunu varsayar (örneğin, EBCDIC kullanan IBM Mainframes üzerinde çalışmaz).
Isaac
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.