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;    
}
skeryl
la source
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);
Jason Nichols
la source
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");
Kashif Khan
la source
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
        }
    }
}
Ted Hopp
la source
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.

GETah
la source
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;
}
Asaph
la source
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();
}
scottt
la source
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 :)

soulcheck
la source
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();    
}
bragboy
la source
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.

digitaljoel
la source
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);

Anatoliy Pelepetz
la source
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