java - example - Equivalente de Guava para IOUtils.toString(InputStream)
ioutils maven (9)
Casi. Podrías usar algo como esto:
InputSupplier<InputStreamReader> readerSupplier = CharStreams.newReaderSupplier
(streamSupplier, Charsets.UTF_8);
String text = CharStreams.toString(readerSupplier);
Personalmente , no creo que IOUtils.toString(InputStream)
sea "agradable", porque siempre usa la codificación predeterminada de la plataforma, que casi nunca es lo que desea. Hay una sobrecarga que toma el nombre de la codificación, pero usar nombres no es una gran idea para IMO. Es por eso que me gusta Charsets.*
.
EDITAR: No es que lo anterior necesite un InputSupplier<InputStream>
como streamSupplier
. Si ya tienes la transmisión, puedes implementarla con la suficiente facilidad:
InputSupplier<InputStream> supplier = new InputSupplier<InputStream>() {
@Override public InputStream getInput() {
return stream;
}
};
Apache Commons IO tiene un buen método de conveniencia IOUtils.toString() para leer un InputStream
en una cadena.
Como trato de alejarme de Apache Commons y de Guava ¿hay un equivalente en Guava? Miré todas las clases en el paquete com.google.common.io
y no pude encontrar nada tan simple.
Editar: entiendo y aprecio los problemas con los conjuntos de caracteres. Sucede que sé que todas mis fuentes están en ASCII (sí, ASCII, no ANSI, etc.), así que en este caso, la codificación no es un problema para mí.
En función de la respuesta aceptada, este es un método de utilidad que se burla del comportamiento de IOUtils.toString()
(y una versión sobrecargada con un juego de caracteres, también). Esta versión debe ser segura, ¿verdad?
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);
}
}
Hay una solución de cierre automático mucho más corta en caso de que la corriente de entrada provenga del recurso classpath:
URL resource = classLoader.getResource(path);
byte[] bytes = Resources.toByteArray(resource);
String text = Resources.toString(resource, StandardCharsets.UTF_8);
Utiliza Guava Resources , inspirado en code.google.com/p/guava-libraries/wiki/IOExplained .
Otra opción es leer los bytes de Stream y crear una cadena a partir de ellos:
new String(ByteStreams.toByteArray(inputStream))
new String(ByteStreams.toByteArray(inputStream), Charsets.UTF_8)
No es guayaba "pura", pero es un poco más corta.
Para un ejemplo concreto, así es como puedo leer un archivo de texto de Android activo:
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;
}
Si tiene una Readable
CharStreams.toString(Readable)
puede usar CharStreams.toString(Readable)
. Entonces, probablemente puedas hacer lo siguiente:
String string = CharStreams.toString( new InputStreamReader( inputStream, "UTF-8" ) );
Te obliga a especificar un juego de caracteres, que supongo que deberías estar haciendo de todos modos.
Usted indicó en su comentario sobre la respuesta de Calum que iba a usar
CharStreams.toString(new InputStreamReader(supplier.get(), Charsets.UTF_8))
Este código es problemático porque la sobrecarga de CharStreams.toString(Readable)
establece:
No cierra la
Readable
.
Esto significa que su InputStreamReader
, y por extensión, el InputStream
devuelto por supplier.get()
, no se cerrará después de que este código se complete.
Si, por otro lado, aprovecha el hecho de que parece que ya tiene un InputSupplier<InputStream>
y usó la sobrecarga CharStreams.toString(InputSupplier<R extends Readable & Closeable>
) CharStreams.toString(InputSupplier<R extends Readable & Closeable>
, el método toString
manejará tanto la creación y cierre del Reader
para usted.
Esto es exactamente lo que Jon Skeet sugirió, excepto que en realidad no hay ninguna sobrecarga de CharStreams.newReaderSupplier
que tome un InputStream
como entrada ... debes darle 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);
El objetivo de InputSupplier
es facilitarle la vida al permitir que Guava maneje las piezas que requieren un feo bloque try-finally
para garantizar que los recursos se cierren adecuadamente.
Editar: Personalmente, encuentro lo siguiente (que es como realmente lo escribiría, simplemente estaba desglosando los pasos en el código anterior)
String text = CharStreams.toString(
CharStreams.newReaderSupplier(supplier, Charsets.UTF_8));
ser mucho menos detallado que esto:
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);
}
Que es más o menos lo que tendrías que escribir para manejar esto correctamente tú mismo.
Edición: febrero de 2014
InputSupplier
y OutputSupplier
y los métodos que los usan han quedado en desuso en Guava 16.0. Sus reemplazos son ByteSource
, CharSource
, ByteSink
y CharSink
. Dado un ByteSource
, ahora puede obtener su contenido como una String
como esta:
ByteSource source = ...
String text = source.asCharSource(Charsets.UTF_8).read();
ACTUALIZACIÓN : Mirando hacia atrás, no me gusta mi solución anterior. Además, es 2013 y ahora hay mejores alternativas disponibles para Java7. Entonces aquí está lo que uso ahora:
InputStream fis = ...;
String text;
try ( InputStreamReader reader = new InputStreamReader(fis, Charsets.UTF_8)){
text = CharStreams.toString(reader);
}
o si con InputSupplier
InputSupplier<InputStreamReader> spl = ...
try ( InputStreamReader reader = spl.getInput()){
text = CharStreams.toString(reader);
}
EDIT (2015): Okio es la mejor abstracción y herramientas para E / S en Java / Android que yo sepa. Lo uso todo el tiempo.
FWIW aquí es lo que uso.
Si ya tengo un flujo en la mano, entonces:
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 estoy creando una transmisión:
String s = CharStreams.toString(CharStreams.newReaderSupplier(new InputSupplier<InputStream>() {
public InputStream getInput() throws IOException {
return <expression creating the stream>;
}
}, Charsets.UTF_8));
Como ejemplo concreto, puedo leer un archivo de texto de Android como este:
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));