Byte UTF-8 [] para String

243

Vamos supor que eu apenas usei a BufferedInputStreampara ler os bytes de um arquivo de texto codificado em UTF-8 em uma matriz de bytes. Eu sei que posso usar a rotina a seguir para converter os bytes em uma cadeia de caracteres, mas existe uma maneira mais eficiente / inteligente de fazer isso do que apenas percorrer os bytes e converter cada um?

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
fonte
17
Por que você não pode simplesmente fazer isso String fileString = new String(_bytes,"UTF-8");?
CoolBeans
1
Como alternativa, você pode usar o BufferedReader para ler em uma matriz de caracteres.
Andy Thomas
@CoolBeans eu poderia se soubesse fazer isso;) Obrigado.
skeryl
Dependendo do tamanho do arquivo, não tenho certeza se carregar o todo byte[]na memória e convertê-lo via new String(_bytes,"UTF-8")(ou mesmo por pedaços com +=a sequência) é o mais eficiente. O encadeamento de InputStreams e Readers pode funcionar melhor, especialmente em arquivos grandes.
22411 Bruno

Respostas:

498

Olhe o construtor para String

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

E se você estiver com preguiça, poderá usar a biblioteca Apache Commons IO para converter diretamente o InputStream em uma String:

String str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
Jason Nichols
fonte
13
Ou de goiaba Charsets.UTF_8 se você estiver em JDK mais velho do que 1,7
siledh
6
Charsets.UTF_8 do uso Goiaba se você estiver em API Android abaixo de 19 também
Ben Clayton
E se checkstyle diz: "Instanciação ilegal: Instanciação de java.lang.String deve ser evitada.", Então o que?
Attila Neparáczki
1
Você pode ver aqui no java.nio.charset.Charset.availableCharsets()mapa todos os caracteres, não apenas os caracteres no StandardCharsets. E se você quiser usar algum outro conjunto de caracteres e ainda assim impedir que o construtor String seja lançado, UnsupportedEncodingExceptionvocê pode usarjava.nio.charset.Charset.forName()
nyxz 15/02/2015
2
IOUtils.toString (inputStream, StandardCharsets.UTF_8) está obsoleto.
Aung Myat Hein
41

A classe Java String possui um construtor interno para converter a matriz de bytes em sequência.

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

String value = new String(byteArray, "UTF-8");
Kashif Khan
fonte
9

Para converter dados utf-8, você não pode assumir uma correspondência 1-1 entre bytes e caracteres. Tente o seguinte:

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

(Bah. Vejo que estou muito lento ao pressionar o botão Postar sua resposta.)

Para ler um arquivo inteiro como uma String, faça algo assim:

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
fonte
4

Você pode usar o String(byte[] bytes) construtor para isso. Veja este link para detalhes. EDIT Você também deve considerar o conjunto de caracteres padrão do seu plateform conforme o documento java:

Constrói uma nova String decodificando a matriz especificada de bytes usando o conjunto de caracteres padrão da plataforma. O comprimento da nova String é uma função do conjunto de caracteres e, portanto, pode não ser igual ao comprimento da matriz de bytes. O comportamento desse construtor quando os bytes fornecidos não são válidos no conjunto de caracteres padrão não é especificado. A classe CharsetDecoder deve ser usada quando for necessário mais controle sobre o processo de decodificação.

GETah
fonte
1
E se seus bytes não estiverem no conjunto de caracteres padrão da plataforma, você pode usar a versão que possui o segundo Charsetargumento para garantir que a conversão esteja correta.
Mike Daniels
1
@ MikeDaniels Na verdade, eu não queria incluir todos os detalhes. Acabei de editar minha resposta
GETah
2

Sabendo que você está lidando com uma matriz de bytes UTF-8, definitivamente desejará usar o construtor String que aceita um nome de conjunto de caracteres . Caso contrário, você poderá se deixar aberto a algumas vulnerabilidades de segurança baseadas em codificação de charset. Observe que ele lança com o UnsupportedEncodingExceptionqual você terá que lidar. Algo assim:

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;
}
Asaph
fonte
2

Aqui está uma função simplificada que lê em bytes e cria uma string. Supõe-se que você provavelmente já saiba em que codificação está o arquivo (e de outra forma é o padrão).

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
fonte
Código editado para tornar o padrão utf-8 para corresponder à pergunta do OP.
Scottt
1

String possui um construtor que usa byte [] e charsetname como parâmetros :)

verificação da alma
fonte
0

Isso também envolve iterar, mas isso é muito melhor do que concatenar cadeias, pois são muito, muito caras.

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
fonte
8
meu querido senhor. String str = new String(byte[])vai fazer muito bem.
zengr 14/12
3
Isso melhora a eficiência, mas não decodifica os dados utf8 corretamente.
quer
0

Por que não obter o que procura desde o início e ler uma sequência do arquivo em vez de uma matriz de bytes? Algo como:

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

depois leia oLinha de dentro até que esteja pronto.

digitaljoel
fonte
Às vezes, é útil manter os delimitadores de linha originais. O OP pode querer isso.
22411 Bruno
0

Eu uso assim

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

Anatoliy Pelepetz
fonte
1
Isso não especifica um conjunto de caracteres, então você obtém o conjunto de caracteres padrão da plataforma que pode não ser UTF-8.
precisa