IOUtils.toString(InputStream)に相当するGuava


106

Apache Commons IOには便利なメソッドがありますInputStream、文字列を読み取るための IOUtils.toString()があります。

私はアパッチコモンズからグアバに移動しようとしているので、グアバに同等のものはありますか?com.google.common.ioパッケージ内のすべてのクラスを調べましたが、これほど単純なものは見つかりませんでした。

編集:私は文字セットの問題を理解し、感謝しています。すべてのソースがASCII(はい、ASCII、ANSIではないなど)であることを知っているので、この場合、エンコーディングは問題になりません。


2
文字セットについて:Charsets.US_ASCII「ええと、どんな文字セットだと思いますか?」多くの人にとって、これは幸せに思えます。特に、JavaはUTF-8のような意味のあるデフォルトを使用しないためです。
ColinD 2010年

知っている。それが私が自分の答えのデフォルトバージョンとしてUTF-8を使用している理由です。
ショーンパトリックフロイド

ドキュメントも参照してください:code.google.com/p/guava-libraries/wiki/IOExplained
Vadzim

@Vadzimこの質問がなされたとき、それらのドキュメントは存在しませんでした:-)
Sean Patrick Floyd

回答:


85

あなたはあなたが使用するつもりであったCalumの答えに関するコメントで述べました

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

このコードは、オーバーロードがCharStreams.toString(Readable)次のように述べるので問題があります。

を閉じませんReadable

これは、このコードが完了した後、あなたのInputStreamReader、さらにはによってInputStream返されたsupplier.get()は閉じられないことを意味します。

一方、すでにを持っているように見え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、グアバが醜いものを必要とする部品を処理できるようにすることであなたの人生をより簡単にすることです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で廃止されました。彼らの置換がありByteSourceCharSourceByteSinkCharSink。を指定すると、ByteSourceその内容を次のStringように取得できます。

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

素晴らしい情報をありがとう(+1)。しかし、これは非常に冗長です。受け入れられた回答をCloseables.closeQuietly()と組み合わせる方が簡単だと思います。
ショーンパトリックフロイド

@CollinD:私は私の答えの1つであなたのメソッドを使用しました。コードを見て、これがInputSupplierを使用する正しい方法であるかどうか教えてください。
Emil

1
@ ColinD、inputStreamがdoPostサーブレットの内部からのものである場合、それを閉じる意味はありますか?(またはそれを閉じることを心配しています)
ブランクマン

CharStreams.toString(InputSupplier)は非推奨になりました。CharSource(asCharSourceを使用してByteSourceから)を作成し、ドキュメントで提案されているようにそのtoStringを使用しました。
ジョンレーマン

4
TedM.Young @:あなたが持っているすべてである場合はInputStream、あなたのようにそれを取得したいStringCharStreams.toString(new InputStreamReader(inputStream, charset))移動するための方法です。ByteSourceまたCharSourceInputStreamsやReadersのソースとして機能できるものがある場合に特に適しています。
ColinD 2014年

56

あなたが持っているReadableなら、あなたは使うことができますCharStreams.toString(Readable)。したがって、おそらく次のことができます。

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

とにかく文字セットを指定するように強制します。


4
実際、私はあなたとジョン・スキートの答えの組み合わせを使用します: `CharStreams.toString(new InputStreamReader(supplier.get()、Charsets.UTF_8))`
Sean Patrick Floyd

はい、オプションを組み合わせる方法はたくさんあります!
Calum

10
@SPFloyd:がある場合は、ではなくInputSupplier<InputStream>を使用することを強くお勧めします。その理由は、与えられたときということで、意志はないに近いこと(基本となるストリームひいてはではありません!)。使用してのために、この方法は、クローズ処理しますあなたのため。CharStreams.newReaderSupplier(supplier, Charsets.UTF_8)new InputStreamReaderInputStreamReadertoStringReaderInputSupplierReadertoStringReader
ColinD 2010年

17

更新:振り返ってみると、古いソリューションは好きではありません。その上、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);
    }

16

ほぼ。あなたはこのようなものを使うことができます:

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

ジョン、request.getInputStreamを介してストリームですか?また、@ Calumの回答で述べたColinDのようにストリームを閉じますか?
ブランクマン

ああ、それはサーブレットのdoPost環境ですが、どうにかしてストリームを閉じますか?
ブランクマン

@ブランクマン:ああ、それがあなたの文脈です-あなたの質問からはまったく明確ではありませんでした。リクエストストリームを閉じるかどうかはそれほど重要ではありませんが、通常は閉じます。私はこの答えを編集します-そのような過負荷はないようです。
Jon Skeet

1
私は今これをやっています:String payLoad = CharStreams.toString(new InputStreamReader(request.getInputStream()、 "UTF-8"));
ブランクマン2012

1
@BeeOnRope:中間的なアプローチの1つはCharsets.UTF_8.name()、タイプミスに強いということです。
Jon Skeet 2013年

11

別のオプションは、Streamからバイトを読み取り、それらから文字列を作成することです。

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

「純粋な」グアバではありませんが、少し短いです。


残念ながら、ByteStreams.toByteArray()Javadocによると、ストリームを閉じません。
錬金術師

それは本当だ。ストリームを閉じるGuavaの機能は見たことがありません。まあ、closeQuietlyを除いて。
ponomandr 2015年

1
通常、ストリームはtry-with-resourcesステートメントで開かれ、自動的に閉じられるため、toByteArray()の責任は負わないはずです
ponomandr

4

受け入れられた回答に基づいて、以下は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);
    }
}

私にはかなり元気に見えます。グアバのIOスタッフは、ワンショットストリームやリーダー(可能な場合)ではなく、再利用可能な入力サプライヤーの観点から考えることを学ぶ場合に最も効果的に機能しますが、大きな変更になる既存のIOUtilsコードを変換しているためと思います。
ColinD 2010年

2
私のグアバ14では、closeQuietlyはすでに非推奨になっています。提案はでこの詳細のJava 7に存在するのtry-と資源の機能を使用することであるcode.google.com/p/guava-libraries/wiki/...
バーティ

2
@AlbertKamは同意しました。しかし、覚えておいてください。この答えは3年前のものです。
Sean Patrick Floyd

@SeanPatrickFloyd:ありがとう!実際、私はあなたの答えから始めて、より新しい解決策を得ました。新しいバージョンを使用している可能性のある他の人にコメントを追加することを考えていました。:)
bertie

4

入力ストリームがクラスパスリソースからのものである場合、自動クローズソリューションははるかに短くなります。

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

IOExplainedに触発されたGuava Resourcesを使用します


1
この質問が出されたとき、Resourcesクラスは存在しませんでしたが、あなたの言うとおりです。今日はおそらくそれが適切な方法です。ありがとう
ショーンパトリックフロイド

2

編集(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));

すべて非推奨になりました。:(
user3562927 2017

1
代わりにgithub.com/square/okioを試してください-GuavaのI / Oをしばらく使用していませんが、
Okioの

0

具体的な例として、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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.