IT-Swarm.Net

相当于IOUtils.toString(InputStream)的番石榴

Apache Commons IO 有一个很方便的方法 IOUtils.toString() 读一个InputStream到一个字符串。.

因为我试图从Apache Commons转移到 Guava :在番石榴中是否有相同的东西?我查看了com.google.common.io包中的所有类,我几乎找不到任何简单的东西。.

编辑: 我理解并欣赏charsets的问题。事实上,我知道所有的源都在ASCII(是的,ASCII,而不是ANSI等),所以在这种情况下,编码对我来说不是问题。.

102
Sean Patrick Floyd

您在评论Calum的回答中说明了您将要使用的内容

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

这段代码有问题,因为重载CharStreams.toString(Readable)表示:

不关闭Readable。.

这意味着在此代码完成后,InputStreamReader以及supplier.get()返回的InputStream扩展名将不会被关闭。.

另一方面,如果你利用了似乎已经有InputSupplier<InputStream>并使用了重载CharStreams.toString(InputSupplier<R extends Readable & Closeable>)这一事实,那么toString方法将为你处理Reader的创建和关闭。.

这正是Jon Skeet所建议的,除了CharStreams.newReaderSupplier实际上没有任何重载,它将InputStream作为输入...你必须给它一个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);

InputSupplier的目的是通过允许Guava处理需要丑陋的try-finally块的部分来确保资源正确关闭,从而使您的生活更轻松。.

编辑: 就个人而言,我发现以下内容(这就是我实际写它的方式,只是打破了上面代码中的步骤)

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

比这更详细:

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

这或多或少是你必须写的,以便自己妥善处理。.


编辑:2014年2月

InputSupplierOutputSupplier以及使用它们的方法已在Guava 16.0中弃用。它们的替换是ByteSourceCharSourceByteSinkCharSink。给定ByteSource,您现在可以将其内容作为String获取,如下所示:

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

快速,可靠且价格合理的云托管

注册并在30天内获得$50奖金!

如果你有Readable,你可以使用CharStreams.toString(Readable)。所以你可以做以下事情:

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

强制你指定一个字符集,我猜你应该这样做。.

55
Calum

_ update _ :回头看,我不喜欢我的旧解决方案。除了它现在是2013年,Java7现在有更好的替代品。所以我现在使用的是:

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

或者如果使用 InputSupplier

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

几乎。你可以使用这样的东西:

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

我个人 不要 认为IOUtils.toString(InputStream)是“好” - 因为它总是使用平台的默认编码,这几乎不是你想要的。有一个重载,它采用编码的名称,但使用名称不是一个好主意IMO。这就是我喜欢Charsets.*的原因。.

编辑:并不是说上面需要一个InputSupplier<InputStream>作为streamSupplier。如果你已经有了这个流,你可以很容易地实现它:

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

另一种选择是从Stream读取字节并从中创建一个String:

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

它不是'纯'番石榴,但它有点短。.

12
ponomandr

根据接受的答案,这里有一个实用工具方法,它可以模拟IOUtils.toString()的行为(以及带有字符集的重载版本)。这个版本应该是安全的,对吗?

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

如果输入流来自类路径资源,则有更短的自动关闭解决方案:

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

使用Guava Resources ,灵感来自 IOExplained 。.

3
Vadzim

_ edit _ (2015): Okio 是我所知道的Java/Android中I/O的最佳抽象和工具。我用它所有的时间。.

FWIW这是我使用的。.

如果我手头有一条流,那么:

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

如果我正在创建一个流:

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

作为一个具体的例子,我可以读取这样的Android文本文件资产:

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

举一个具体的例子,这是我如何阅读Android文本文件资产:

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