Octet UTF-8 [] en chaîne


243

Supposons que je viens d'utiliser un BufferedInputStreampour lire les octets d'un fichier texte encodé UTF-8 dans un tableau d'octets. Je sais que je peux utiliser la routine suivante pour convertir les octets en chaîne, mais y a-t-il un moyen plus efficace / plus intelligent de faire cela que de simplement parcourir les octets et de convertir chacun?

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

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

    return file_string;    
}

17
Pourquoi tu ne peux pas faire ça String fileString = new String(_bytes,"UTF-8");?
CoolBeans

1
Alternativement, vous pouvez utiliser BufferedReader pour lire dans un tableau de caractères.
Andy Thomas


@CoolBeans je pourrais si j'avais su le faire;) Merci.
skeryl

Selon la taille du fichier, je ne suis pas sûr de charger le tout byte[]en mémoire et de le convertir via new String(_bytes,"UTF-8")(ou même par morceaux avec +=sur la chaîne) est le plus efficace. Le chaînage des flux d'entrée et des lecteurs peut fonctionner mieux, en particulier sur les fichiers volumineux.
Bruno

Réponses:


498

Regardez le constructeur de String

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

Et si vous vous sentez paresseux, vous pouvez utiliser la bibliothèque d' E / S Apache Commons pour convertir directement le InputStream en une chaîne:

String str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

13
Ou Guava's Charsets.UTF_8 si vous êtes sur JDK plus vieux que 1.7
siledh

6
Utilisez Charsets.UTF_8 de Guava si vous utilisez également l'API Android en dessous de 19
Ben Clayton

Et si checkstyle dit: "Instanciation illégale: l'instanciation de java.lang.String doit être évitée.", Alors quoi?
Attila Neparáczki

1
Vous pouvez voir ici la java.nio.charset.Charset.availableCharsets()carte tous les jeux de caractères et pas seulement les jeux de caractères dans le StandardCharsets. Et si vous voulez utiliser un autre jeu de caractères et que vous voulez toujours empêcher le constructeur de String de lancer, UnsupportedEncodingExceptionvous pouvez utiliserjava.nio.charset.Charset.forName()
nyxz

2
IOUtils.toString (inputStream, StandardCharsets.UTF_8) est désormais obsolète.
Aung Myat Hein,

41

La classe Java String possède un constructeur intégré pour convertir le tableau d'octets en chaîne.

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

String value = new String(byteArray, "UTF-8");

9

Pour convertir des données utf-8, vous ne pouvez pas supposer une correspondance 1-1 entre octets et caractères. Essaye ça:

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

(Bah. Je vois que je suis en train de ralentir en appuyant sur le bouton Publier votre réponse.)

Pour lire un fichier entier en tant que chaîne, faites quelque chose comme ceci:

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
        }
    }
}

4

Vous pouvez utiliser le String(byte[] bytes) constructeur pour cela. Voir ce lien pour plus de détails. EDIT Vous devez également prendre en compte le jeu de caractères par défaut de votre plateforme conformément au document java:

Construit une nouvelle chaîne en décodant le tableau d'octets spécifié à l'aide du jeu de caractères par défaut de la plate-forme. La longueur de la nouvelle chaîne est fonction du jeu de caractères et peut donc ne pas être égale à la longueur du tableau d'octets. Le comportement de ce constructeur lorsque les octets donnés ne sont pas valides dans le jeu de caractères par défaut n'est pas spécifié. La classe CharsetDecoder doit être utilisée lorsqu'un contrôle accru du processus de décodage est requis.


1
Et si vos octets ne sont pas dans le jeu de caractères par défaut de la plateforme, vous pouvez utiliser la version qui a le deuxième Charsetargument pour vous assurer que la conversion est correcte.
Mike Daniels

1
@MikeDaniels En effet, je ne voulais pas inclure tous les détails. Je
viens de modifier


2

Sachant que vous avez affaire à un tableau d'octets UTF-8, vous voudrez certainement utiliser le constructeur String qui accepte un nom de jeu de caractères . Sinon, vous risquez de vous exposer à certaines vulnérabilités de sécurité basées sur le codage de charset. Notez qu'il lance UnsupportedEncodingExceptionce que vous devrez gérer. Quelque chose comme ça:

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;
}

2

Voici une fonction simplifiée qui lira en octets et créera une chaîne. Il suppose que vous savez probablement déjà dans quel encodage le fichier se trouve (et sinon par défaut).

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();
}

Code modifié pour que la valeur par défaut soit utf-8 pour correspondre à la question de l'OP.
scottt

1

La chaîne a un constructeur qui prend l'octet [] et le nom de jeu de caractères comme paramètres :)


0

Cela implique également l'itération, mais c'est beaucoup mieux que la concaténation de chaînes car elles sont très très coûteuses.

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();    
}

8
mon cher seigneur. String str = new String(byte[])fera très bien.
zengr

3
Cela améliore l'efficacité, mais il ne décode pas correctement les données utf8.
Ted Hopp

0

Pourquoi ne pas obtenir ce que vous recherchez dès le départ et lire une chaîne du fichier au lieu d'un tableau d'octets? Quelque chose comme:

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

puis lisez en ligne jusqu'à ce que ce soit fait.


Parfois, il est utile de conserver les délimiteurs de ligne d'origine. Le PO pourrait vouloir cela.
Bruno

0

J'utilise de cette façon

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


1
Cela ne spécifie pas de jeu de caractères, vous obtenez donc le jeu de caractères par défaut de la plate-forme qui peut ne pas être UTF-8.
greg-449
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.