web-dev-qa-db-fra.com

Équivalent goyave pour IOUtils.toString (InputStream)

Apache Commons IO a une méthode pratique de Nice IOUtils.toString () pour lire un InputStream en une chaîne.

Depuis que je tente de quitter Apache Commons et de passer à Guava : existe-t-il un équivalent en goyave? J'ai regardé toutes les classes du com.google.common.io package et je n'ai rien trouvé d'aussi simple.

Edit: Je comprends et apprécie les problèmes liés aux jeux de caractères. Il se trouve que je sais que toutes mes sources sont en ASCII (oui, en ASCII, pas en ANSI, etc.)). Dans ce cas, le codage ne me pose aucun problème.

104
Sean Patrick Floyd

Vous avez indiqué dans votre commentaire sur la réponse de Calum que vous alliez utiliser

CharStreams.toString(new InputStreamReader(supplier.get(), Charsets.UTF_8))

Ce code est problématique car la surcharge CharStreams.toString(Readable) déclare:

Ne ferme pas le Readable.

Cela signifie que votre InputStreamReader et, par extension, le InputStream renvoyé par supplier.get(), ne seront pas fermés une fois ce code terminé.

Si, par contre, vous tirez parti du fait que vous semblez déjà avoir un InputSupplier<InputStream> Et utiliser la surcharge CharStreams.toString(InputSupplier<R extends Readable & Closeable>), La méthode toString gérera à la fois création et fermeture du Reader pour vous.

C'est exactement ce que Jon Skeet a suggéré, sauf qu'il n'y a aucune surcharge de CharStreams.newReaderSupplier Qui prenne un InputStream en entrée ... vous devez lui donner un InputSupplier :

InputSupplier<? extends InputStream> supplier = ...
InputSupplier<InputStreamReader> readerSupplier = 
    CharStreams.newReaderSupplier(supplier, Charsets.UTF_8);

// InputStream and Reader are both created and closed in this single call
String text = CharStreams.toString(readerSupplier);

Le but de InputSupplier est de vous simplifier la vie en permettant à Guava de gérer les parties qui nécessitent un bloc try-finally Laid afin de s’assurer que les ressources sont fermées correctement.

Edit: Personnellement, je trouve ce qui suit (c’est ainsi que j’écrivais, c’était en train de décomposer les étapes du code ci-dessus)

String text = CharStreams.toString(
    CharStreams.newReaderSupplier(supplier, Charsets.UTF_8));

être loin moins verbeux que cela:

String text;
InputStreamReader reader = new InputStreamReader(supplier.get(), 
    Charsets.UTF_8);
boolean threw = true;
try {
  text = CharStreams.toString(reader);
  threw = false;
}
finally {
  Closeables.close(reader, threw);
}

Ce qui est plus ou moins ce que vous auriez à écrire pour gérer cela vous-même correctement.


Edit: Février 2014

InputSupplier et OutputSupplier et les méthodes qui les utilisent sont obsolètes dans Guava 16.0. Leurs remplaçants sont ByteSource, CharSource, ByteSink et CharSink. Étant donné un ByteSource, vous pouvez maintenant obtenir son contenu sous la forme d'un String comme ceci:

ByteSource source = ...
String text = source.asCharSource(Charsets.UTF_8).read();
82
ColinD

Si vous avez un Readable, vous pouvez utiliser CharStreams.toString(Readable). Donc, vous pouvez probablement faire ce qui suit:

String string = CharStreams.toString( new InputStreamReader( inputStream, "UTF-8" ) );

Vous oblige à spécifier un jeu de caractères, ce que je suppose que vous devriez faire de toute façon.

55
Calum

UPDATE : En regardant en arrière, je n'aime pas mon ancienne solution. En outre, nous sommes en 2013 et de meilleures alternatives sont maintenant disponibles pour Java7. Alors voici ce que j'utilise maintenant:

InputStream fis = ...;
String text;
try (  InputStreamReader reader = new InputStreamReader(fis, Charsets.UTF_8)){
        text = CharStreams.toString(reader);
}

ou si avec InputSupplier

InputSupplier<InputStreamReader> spl = ...
try (  InputStreamReader reader = spl.getInput()){
        text = CharStreams.toString(reader);
    }
15
husayt

Presque. Vous pouvez utiliser quelque chose comme ceci:

InputSupplier<InputStreamReader> readerSupplier = CharStreams.newReaderSupplier
    (streamSupplier, Charsets.UTF_8);
String text = CharStreams.toString(readerSupplier);

Personnellement, je ne pas pense que IOUtils.toString(InputStream) est "gentil" - car il utilise toujours l'encodage par défaut de la plate-forme, ce qui n'est presque jamais ce que vous voulez. Il y a une surcharge qui prend le nom de l'encodage, mais utiliser des noms n'est pas une bonne idée, OMI. C'est pourquoi j'aime bien Charsets.*.

EDIT: Non que ce qui précède nécessite un InputSupplier<InputStream> Comme le streamSupplier. Si vous avez déjà le flux, vous pouvez l'implémenter assez facilement cependant:

InputSupplier<InputStream> supplier = new InputSupplier<InputStream>() {
    @Override public InputStream getInput() {
        return stream;
    }
};
15
Jon Skeet

Une autre option consiste à lire des octets à partir de Stream et à en créer une chaîne:

new String(ByteStreams.toByteArray(inputStream))
new String(ByteStreams.toByteArray(inputStream), Charsets.UTF_8)

Ce n'est pas de la pure goyave, mais un peu plus courte.

11
ponomandr

Sur la base de la réponse acceptée, voici une méthode utilitaire qui modifie le comportement de IOUtils.toString() (ainsi qu'une version surchargée avec un jeu de caractères). Cette version devrait être sûre, non?

public static String toString(final InputStream is) throws IOException{
    return toString(is, Charsets.UTF_8);
}


public static String toString(final InputStream is, final Charset cs)
throws IOException{
    Closeable closeMe = is;
    try{
        final InputStreamReader isr = new InputStreamReader(is, cs);
        closeMe = isr;
        return CharStreams.toString(isr);
    } finally{
        Closeables.closeQuietly(closeMe);
    }
}
4
Sean Patrick Floyd

Il existe une solution de fermeture automatique beaucoup plus courte au cas où le flux d'entrée provient d'une ressource classpath:

URL resource = classLoader.getResource(path);
byte[] bytes = Resources.toByteArray(resource);
String text = Resources.toString(resource, StandardCharsets.UTF_8);

Utilise des ressources de goyave , inspirées de IO Explained .

3
Vadzim

[~ # ~] éditer [~ # ~] (2015): Okio est la meilleure abstraction et les meilleurs outils pour moi/O en Java/Android que je connais. Je l'utilise tout le temps.

FWIW voici ce que j'utilise.

Si j'ai déjà un flux en main, alors:

final InputStream stream; // this is received from somewhere
String s = CharStreams.toString(CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
    public InputStream getInput() throws IOException {
        return stream;
    }
}, Charsets.UTF_8));

Si je crée un flux:

String s = CharStreams.toString(CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
    public InputStream getInput() throws IOException {
        return <expression creating the stream>;
    }
}, Charsets.UTF_8));

À titre d'exemple concret, je peux lire un fichier Android) comme ceci:

final Context context = ...;
String s = CharStreams.toString(CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
    public InputStream getInput() throws IOException {
        return context.getAssets().open("my_asset.txt");
    }
}, Charsets.UTF_8));
2
orip

Pour un exemple concret, voici comment je peux lire un fichier Android fichier texte:

public static String getAssetContent(Context context, String file) {
    InputStreamReader reader = null;
    InputStream stream = null;
    String output = "";

    try {
        stream = context.getAssets().open(file);
        reader = new InputStreamReader(stream, Charsets.UTF_8);
        output = CharStreams.toString(reader);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    return output;
}
0
TruMan1