Apache Commons IO有一个很好的便捷方法IOUtils.toString()来读取InputStream
字符串。
由于我正尝试从Apache Commons转移到Guava:Guava中有等同的功能吗?我查看了com.google.common.io
程序包中的所有类,但几乎找不到任何简单的东西。
编辑:我理解并赞赏字符集的问题。碰巧,我知道我所有的来源都是ASCII(是,ASCII,不是ANSI等),因此在这种情况下,编码对我来说不是问题。
Apache Commons IO有一个很好的便捷方法IOUtils.toString()来读取InputStream
字符串。
由于我正尝试从Apache Commons转移到Guava:Guava中有等同的功能吗?我查看了com.google.common.io
程序包中的所有类,但几乎找不到任何简单的东西。
编辑:我理解并赞赏字符集的问题。碰巧,我知道我所有的来源都是ASCII(是,ASCII,不是ANSI等),因此在这种情况下,编码对我来说不是问题。
Answers:
您在对Calum答案的评论中表示要使用
CharStreams.toString(new InputStreamReader(supplier.get(), Charsets.UTF_8))
该代码是有问题的,因为重载CharStreams.toString(Readable)
指出:
不关闭
Readable
。
这意味着在此代码完成后,您的InputStreamReader
,以及作为扩展名的InputStream
by supplier.get()
将不会关闭。
另一方面,如果您利用了似乎已经具有InputSupplier<InputStream>
和使用过重载的事实CharStreams.toString(InputSupplier<R extends Readable & Closeable>
,则该toString
方法将同时处理Reader
。
这正是乔恩斯基特建议,但没有真正的任何过载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月
InputSupplier
并且OutputSupplier
在Guava 16.0中已弃用使用它们的方法。其接替者ByteSource
,CharSource
,ByteSink
和CharSink
。给定一个ByteSource
,您现在可以String
像这样获取其内容:
ByteSource source = ...
String text = source.asCharSource(Charsets.UTF_8).read();
InputStream
,而您想将其作为一个String
,那CharStreams.toString(new InputStreamReader(inputStream, charset))
就是要走的路。ByteSource
并且CharSource
是专门为在那里你有什么事情,可以作为源起案件InputStream
秒或Reader
秒。
如果您有Readable
可以使用CharStreams.toString(Readable)
。因此,您可以执行以下操作:
String string = CharStreams.toString( new InputStreamReader( inputStream, "UTF-8" ) );
强迫您指定一个字符集,我想您还是应该这样做。
InputSupplier<InputStream>
建议,我强烈建议使用CharStreams.newReaderSupplier(supplier, Charsets.UTF_8)
而不是new InputStreamReader
。原因是,给定时InputStreamReader
,toString
将不会关闭它Reader
(因此不会关闭基础流!)。通过将InputSupplier
for用作Reader
,该toString
方法将为您处理关闭Reader
。
更新:回想一下,我不喜欢我的旧解决方案。除了现在是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);
}
几乎。您可以使用如下形式:
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;
}
};
Charsets.UTF_8.name()
-更好的防错字。
另一个选择是从Stream读取字节并从它们创建一个String:
new String(ByteStreams.toByteArray(inputStream))
new String(ByteStreams.toByteArray(inputStream), Charsets.UTF_8)
它不是“纯”的番石榴,但是要短一些。
ByteStreams.toByteArray()
根据Javadoc的说法,它不会关闭流。
根据公认的答案,这是一种实用程序方法,可以模拟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);
}
}
如果输入流来自类路径资源,则自动关闭解决方案要短得多:
URL resource = classLoader.getResource(path);
byte[] bytes = Resources.toByteArray(resource);
String text = Resources.toString(resource, StandardCharsets.UTF_8);
使用受IOExplained启发的番石榴资源。
编辑(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));
作为一个具体的示例,这是我如何读取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;
}
Charsets.US_ASCII
),而不是让您说“嗯,我猜是什么字符集?” 仍然很好。这对许多人来说似乎都很高兴。尤其是因为Java不使用有意义的默认值,例如UTF-8。