Ekwiwalent guawy dla juty.toString(InputStream)

Apache Commons IO ma wygodną metodę IOUtils.toString () do odczytu InputStream do ciągu znaków.

Ponieważ staram się odejść od Apache Commons i do Guava : Czy Jest jakiś odpowiednik w Guava? Przejrzałem wszystkie klasy w pakiecie com.google.common.io i nie mogłem znaleźć niczego tak prostego.

Edit: Rozumiem i doceniam problemy z zestawami znaków. Tak się składa, że wiem, że wszystkie moje źródła są w ASCII (tak, ASCII, nie ANSI itp.), więc w tym przypadku kodowanie nie jest dla mnie problemem.

Author: Jonik, 2010-11-15

9 answers

W komentarzu do odpowiedzi Caluma napisałeś, że użyjesz

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

Ten kod jest problematyczny, ponieważ przeciążenie CharStreams.toString(Readable) stwierdza:

Nie zamyka Readable.

Oznacza to, że twoje InputStreamReader, a przez to InputStream zwrócone przez supplier.get(), nie zostaną zamknięte po zakończeniu tego kodu.

Jeśli z drugiej strony wykorzystasz fakt, że wydaje się, że masz już InputSupplier<InputStream> i użyłeś przeciążenia CharStreams.toString(InputSupplier<R extends Readable & Closeable>), toString metoda zajmie się zarówno tworzeniem, jak i zamykaniem Reader.

To jest dokładnie to, co zasugerował Jon Skeet, z wyjątkiem tego, że nie ma żadnego przeciążenia CharStreams.newReaderSupplier, które bierze InputStream jako wejście... musisz dać 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);

Celem InputSupplier jest ułatwienie sobie życia, pozwalając Guava obsługiwać części, które wymagają brzydkiego bloku try-finally, aby zapewnić prawidłowe zamknięcie zasobów.

Edit: osobiście uważam, że (tak właśnie napisałbym to, po prostu rozbijając kroki w powyższym kodzie)

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

Być daleko mniej gadatliwe niż to:

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

Czyli mniej więcej to, co musiałbyś napisać, żeby samemu sobie z tym poradzić.


Edit: Luty 2014

InputSupplier i OutputSupplier i metody, które z nich korzystają, zostały wycofane w Guava 16.0. Ich zastępcami są ByteSource, CharSource, ByteSink i CharSink. Biorąc pod uwagę ByteSource, możesz teraz uzyskać jego zawartość jako String w ten sposób:

ByteSource source = ...
String text = source.asCharSource(Charsets.UTF_8).read();
 80
Author: ColinD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-05 17:51:11

Jeśli masz Readable możesz użyć CharStreams.toString(Readable). Więc prawdopodobnie możesz wykonać następujące czynności:

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

Zmusza cię do określenia zestawu znaków, co I tak powinieneś robić.

 54
Author: Calum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-15 15:12:04

Prawie. Przydałoby się coś takiego:

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

Osobiście ja nie uważam, że IOUtils.toString(InputStream) jest "ładny" - ponieważ zawsze używa domyślnego kodowania platformy, co prawie nigdy nie jest tym, czego chcesz. Jest przeciążenie, które przyjmuje nazwę kodowania, ale używanie nazw nie jest dobrym pomysłem IMO. Dlatego lubię Charsets.*.

EDIT: Nie, żeby powyższe wymagało InputSupplier<InputStream> jako streamSupplier. Jeśli masz już strumień, możesz to łatwo zaimplementować chociaż:

InputSupplier<InputStream> supplier = new InputSupplier<InputStream>() {
    @Override public InputStream getInput() {
        return stream;
    }
};
 15
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-15 22:35:54

UPDATE : patrząc wstecz, nie podoba mi się moje stare rozwiązanie. Poza tym jest 2013 teraz i są lepsze alternatywy dostępne teraz dla Java7. Oto, czego teraz używam:

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

Lub jeśli z InputSupplier

InputSupplier<InputStreamReader> spl = ...
try (  InputStreamReader reader = spl.getInput()){
        text = CharStreams.toString(reader);
    }
 14
Author: husayt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-14 15:10:39

Inną opcją jest odczyt bajtów ze strumienia i utworzenie z nich ciągu znaków:

new String(ByteStreams.toByteArray(inputStream))
new String(ByteStreams.toByteArray(inputStream), Charsets.UTF_8)
Nie jest to "czysta" guawa, ale jest trochę krótsza.
 12
Author: ponomandr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-30 16:36:11

W oparciu o zaakceptowaną odpowiedź, oto metoda użytkowa, która wyśmiewa zachowanie IOUtils.toString() (i przeciążoną wersję z charset, jak również). Ta wersja powinna być bezpieczna, prawda?

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
Author: Sean Patrick Floyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-15 16:52:56

Istnieje znacznie krótsze rozwiązanie autoklozujące w przypadku, gdy strumień wejściowy pochodzi z zasobu classpath:

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

Wykorzystuje zasoby Guava , inspirowane IOExplained .

 3
Author: Vadzim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-29 12:59:18

Edytuj (2015): Okio {[7] } jest najlepszą abstrakcją i narzędziami do I/O w Javie / Android, jakie znam. Używam go cały czas.

FWIW oto czego używam.

Jeśli już mam strumień w ręku, to:

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

Jeśli tworzę strumień:

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

Jako konkretny przykład mogę odczytać plik tekstowy Androida w taki sposób:

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
Author: orip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-24 12:45:31

Dla konkretnego przykładu, Oto Jak mogę odczytać plik tekstowy Androida:

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
Author: TruMan1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-03 15:11:15