UTF-8 byte [] a String

243

Supongamos que acabo de utilizar a BufferedInputStreampara leer los bytes de un archivo de texto codificado UTF-8 en una matriz de bytes. Sé que puedo usar la siguiente rutina para convertir los bytes en una cadena, pero ¿hay una manera más eficiente / inteligente de hacer esto que simplemente iterar a través de los bytes y convertir cada uno?

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
fuente
17
¿Por qué no puedes hacer esto String fileString = new String(_bytes,"UTF-8");?
CoolBeans
1
Alternativamente, puede usar BufferedReader para leer en una matriz de caracteres.
Andy Thomas
@CoolBeans podría si hubiera sabido hacer eso;) Gracias.
skeryl
Dependiendo del tamaño del archivo, no estoy seguro de que cargar todo byte[]en la memoria y convertirlo a través de new String(_bytes,"UTF-8")(o incluso por fragmentos con +=la cadena) sea lo más eficiente. El encadenamiento de InputStreams y lectores podría funcionar mejor, especialmente en archivos grandes.
Bruno

Respuestas:

498

Mira el constructor de String

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

Y si se siente flojo, puede usar la biblioteca IO de Apache Commons para convertir el InputStream en una cadena directamente:

String str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
Jason Nichols
fuente
13
O Charsets de Guava.UTF_8 si está en JDK anterior a 1.7
siledh
66
Use Guava's Charsets.UTF_8 si también está en la API de Android por debajo de 19
Ben Clayton
Y si checkstyle dice: "Instanciación ilegal: se debe evitar la creación de instancias de java.lang.String", ¿entonces qué?
Attila Neparáczki
1
Puede ver aquí el java.nio.charset.Charset.availableCharsets()mapa de todos los conjuntos de caracteres, no solo los conjuntos de caracteres StandardCharsets. Y si desea usar algún otro juego de caracteres y aún así quiere evitar que el constructor de cadenas se lance UnsupportedEncodingException, puede usarjava.nio.charset.Charset.forName()
nyxz
2
IOUtils.toString (inputStream, StandardCharsets.UTF_8) está en desuso ahora.
Aung Myat Hein
41

La clase Java String tiene un constructor incorporado para convertir la matriz de bytes en una cadena.

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

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

Para convertir datos utf-8, no puede asumir una correspondencia 1-1 entre bytes y caracteres. Prueba esto:

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

(Bah. Veo que soy lento para presionar el botón Publicar su respuesta).

Para leer un archivo completo como una cadena, haga algo como esto:

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

Puedes usar el String(byte[] bytes) constructor para eso. Vea este enlace para más detalles. EDITAR También debe tener en cuenta el juego de caracteres predeterminado de su plataforma según el documento de Java:

Construye una nueva cadena decodificando la matriz de bytes especificada utilizando el juego de caracteres predeterminado de la plataforma. La longitud de la nueva cadena es una función del conjunto de caracteres y, por lo tanto, puede no ser igual a la longitud de la matriz de bytes. El comportamiento de este constructor cuando los bytes dados no son válidos en el juego de caracteres predeterminado no está especificado. La clase CharsetDecoder debe usarse cuando se requiere más control sobre el proceso de decodificación.

GETah
fuente
1
Y si sus bytes no están en el juego de caracteres predeterminado de la plataforma, puede usar la versión que tiene el segundo Charsetargumento para asegurarse de que la conversión sea correcta.
Mike Daniels
1
@MikeDaniels De hecho, no quería incluir todos los detalles. Acaba de editar mi respuesta
getah
2

Sabiendo que está tratando con una matriz de bytes UTF-8, definitivamente querrá usar el constructor de cadenas que acepte un nombre de conjunto de caracteres . De lo contrario, puede dejar algunas vulnerabilidades de seguridad basadas en la codificación de caracteres. Tenga en cuenta que arroja UnsupportedEncodingExceptionlo que tendrá que manejar. Algo como esto:

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
fuente
2

Aquí hay una función simplificada que leerá en bytes y creará una cadena. Supone que probablemente ya sepa en qué codificación se encuentra el archivo (y, de lo contrario, está predeterminado).

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();
}
scottt
fuente
Código editado para que el valor predeterminado sea utf-8 para que coincida con la pregunta del OP.
scottt
1

La cadena tiene un constructor que toma byte [] y charsetname como parámetros :)

verificación del alma
fuente
0

Esto también implica iterar, pero esto es mucho mejor que concatenar cadenas ya que son muy costosas.

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();    
}
fanfarrón
fuente
8
mi querido señor String str = new String(byte[])hará bien.
zengr
3
Esto mejora la eficiencia, pero no decodifica los datos utf8 correctamente.
Ted Hopp
0

¿Por qué no obtener lo que está buscando desde el principio y leer una cadena del archivo en lugar de una matriz de bytes? Algo como:

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

luego lea la línea desde adentro hasta que esté lista.

digitaljoel
fuente
A veces, es útil mantener los delimitadores de línea originales. El OP podría querer eso.
Bruno
0

Yo uso de esta manera

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

Anatoliy Pelepetz
fuente
1
Esto no especifica un conjunto de caracteres, por lo que obtienes el conjunto de caracteres predeterminado de la plataforma que bien puede no ser UTF-8.
greg-449