UTF-8 bajt [] na String

243

Załóżmy, że właśnie użyłem a BufferedInputStreamdo odczytania bajtów pliku tekstowego zakodowanego w UTF-8 do tablicy bajtów. Wiem, że mogę użyć poniższej procedury do konwersji bajtów na ciąg, ale czy istnieje bardziej wydajny / mądrzejszy sposób na zrobienie tego niż tylko iteracja po bajtach i konwersja każdego z nich?

public String openFileToString(byte[] _bytes)
{
    String file_string = "";

    for(int i = 0; i < _bytes.length; i++)
    {
        file_string += (char)_bytes[i];
    }

    return file_string;    
}
skeryl
źródło
17
Dlaczego nie możesz tego po prostu zrobić String fileString = new String(_bytes,"UTF-8");?
CoolBeans,
1
Alternatywnie możesz użyć BufferedReader do odczytu do tablicy char.
Andy Thomas
@CoolBeans Mógłbym, gdybym wiedział, że to zrobić;) Dziękuję.
skeryl
W zależności od rozmiaru pliku, nie jestem pewien, czy ładuję całość byte[]do pamięci i konwertuje ją przez new String(_bytes,"UTF-8")(lub nawet fragmenty za pomocą+= ciągiem) jest najbardziej wydajna. Łączenie strumieni wejściowych i czytników może działać lepiej, szczególnie w przypadku dużych plików.
Bruno

Odpowiedzi:

498

Spójrz na konstruktor String

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

A jeśli czujesz się leniwy, możesz skorzystać z biblioteki Apache Commons IO do bezpośredniej konwersji InputStream na String:

String str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
Jason Nichols
źródło
13
Lub Gusets 's Charsets.UTF_8, jeśli masz JDK starsze niż 1.7
siledh
6
Użyj Gusets's Charsets.UTF_8, jeśli używasz Androida API również poniżej 19 lat
Ben Clayton
A jeśli checkstyle mówi: „Nielegalne tworzenie instancji: należy unikać tworzenia java.lang.String.”, To co?
Attila Neparáczki
1
Tutaj możesz zobaczyć java.nio.charset.Charset.availableCharsets()mapę wszystkich zestawów znaków, a nie tylko zestawów znaków w StandardCharsets. A jeśli chcesz użyć innego zestawu znaków i nadal chcesz zapobiec rzucaniu się konstruktora String UnsupportedEncodingException, możesz użyćjava.nio.charset.Charset.forName()
nyxz
2
IOUtils.toString (inputStream, StandardCharsets.UTF_8) jest już nieaktualny.
Aung Myat Hein
41

Klasa Java String ma wbudowany konstruktor do konwersji tablicy bajtów na ciąg znaków.

byte[] byteArray = new byte[] {87, 79, 87, 46, 46, 46};

String value = new String(byteArray, "UTF-8");
Kashif Khan
źródło
9

Aby przekonwertować dane utf-8, nie można zakładać zgodności 1-1 między bajtami i znakami. Spróbuj tego:

String file_string = new String(bytes, "UTF-8");

(Bah. Widzę, że wolę naciskać przycisk Opublikuj swoją odpowiedź).

Aby odczytać cały plik jako ciąg znaków, wykonaj coś takiego:

public String openFileToString(String fileName) throws IOException
{
    InputStream is = new BufferedInputStream(new FileInputStream(fileName));

    try {
        InputStreamReader rdr = new InputStreamReader(is, "UTF-8");
        StringBuilder contents = new StringBuilder();
        char[] buff = new char[4096];
        int len = rdr.read(buff);
        while (len >= 0) {
            contents.append(buff, 0, len);
        }
        return buff.toString();
    } finally {
        try {
            is.close();
        } catch (Exception e) {
            // log error in closing the file
        }
    }
}
Ted Hopp
źródło
4

Możesz do tego użyć String(byte[] bytes) konstruktora. Zobacz ten link, aby uzyskać szczegółowe informacje. EDYCJA Musisz także wziąć pod uwagę domyślny zestaw znaków swojej płyty zgodnie z dokumentacją java:

Konstruuje nowy ciąg, dekodując określoną tablicę bajtów przy użyciu domyślnego zestawu znaków platformy. Długość nowego ciągu znaków jest funkcją zestawu znaków, a zatem może nie być równa długości tablicy bajtów. Zachowanie tego konstruktora, gdy podane bajty nie są prawidłowe w domyślnym zestawie znaków, nie jest określone. Klasa CharsetDecoder powinna być używana, gdy wymagana jest większa kontrola nad procesem dekodowania.

GETah
źródło
1
A jeśli twoje bajty nie znajdują się w domyślnym zestawie znaków platformy, możesz użyć wersji z drugim Charsetargumentem, aby upewnić się, że konwersja jest poprawna.
Mike Daniels,
1
@MikeDaniels Rzeczywiście, nie chciałem podawać wszystkich szczegółów. Właśnie zredagowałem moją odpowiedź
GETah
2

Wiedząc, że masz do czynienia z tablicą bajtów UTF-8, na pewno będziesz chciał użyć konstruktora String, który akceptuje nazwę zestawu znaków . W przeciwnym razie możesz narazić się na pewne luki w zabezpieczeniach oparte na kodowaniu zestawu znaków. Pamiętaj, że rzuca, z UnsupportedEncodingExceptionczym będziesz musiał sobie poradzić. Coś takiego:

public String openFileToString(String fileName) {
    String file_string;
    try {
        file_string = new String(_bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        // this should never happen because "UTF-8" is hard-coded.
        throw new IllegalStateException(e);
    }
    return file_string;
}
Asaf
źródło
2

Oto uproszczona funkcja, która odczytuje bajty i tworzy ciąg znaków. Zakłada się, że prawdopodobnie już wiesz, w jakim kodowaniu znajduje się plik (a poza tym domyślnie).

static final int BUFF_SIZE = 2048;
static final String DEFAULT_ENCODING = "utf-8";

public static String readFileToString(String filePath, String encoding) throws IOException {

    if (encoding == null || encoding.length() == 0)
        encoding = DEFAULT_ENCODING;

    StringBuffer content = new StringBuffer();

    FileInputStream fis = new FileInputStream(new File(filePath));
    byte[] buffer = new byte[BUFF_SIZE];

    int bytesRead = 0;
    while ((bytesRead = fis.read(buffer)) != -1)
        content.append(new String(buffer, 0, bytesRead, encoding));

    fis.close();        
    return content.toString();
}
Scott
źródło
Edytowano kod, aby domyślnym był utf-8, pasujący do pytania OP.
Scott
1

Łańcuch ma konstruktor, który przyjmuje parametry byte [] i charsetname jako parametry :)

soulcheck
źródło
0

Obejmuje to również iterację, ale jest to znacznie lepsze niż łączenie łańcuchów, ponieważ są one bardzo bardzo kosztowne.

public String openFileToString(String fileName)
{
    StringBuilder s = new StringBuilder(_bytes.length);

    for(int i = 0; i < _bytes.length; i++)
    {
        s.append((char)_bytes[i]);
    }

    return s.toString();    
}
bragboy
źródło
8
mój drogi panie. String str = new String(byte[])zrobi dobrze.
zengr
3
Zwiększa to wydajność, ale nie dekoduje poprawnie danych utf8.
Ted Hopp,
0

Dlaczego nie wziąć tego, czego szukasz od samego początku i przeczytać ciąg z pliku zamiast tablicy bajtów? Coś jak:

BufferedReader in = new BufferedReader(new InputStreamReader( new FileInputStream( "foo.txt"), Charset.forName( "UTF-8"));

następnie czytaj Linia od wewnątrz, aż się skończy.

digitaljoel
źródło
Czasami warto zachować oryginalne ograniczniki linii. OP może tego chcieć.
Bruno
0

Używam w ten sposób

String strIn = new String(_bytes, 0, numBytes);

Anatoliy Pelepetz
źródło
1
Nie określa to zestawu znaków, więc otrzymujesz domyślny zestaw znaków platformy, który może nie być UTF-8.
greg-449