IOUtils.toString (InputStream)에 해당하는 Guava


106

Apache Commons IO 에는 문자열 을 읽을 수있는 편리한 메서드 IOUtils.toString ()InputStream있습니다.

Apache Commons에서 Guava 로 이동하려고하므로 Guava 에 동등한 기능이 있습니까? com.google.common.io패키지의 모든 클래스를 살펴 보았지만 거의 간단한 것을 찾을 수 없었습니다.

편집 : 나는 문자 세트와 관련된 문제를 이해하고 감사합니다. 내 모든 소스가 ASCII (예, ​​ASCII, ANSI 등이 아님)라는 것을 알고 있으므로이 경우 인코딩은 문제가되지 않습니다.


2
문자셋에 대하여 : 라이브러리에서 Charsets.US_ASCII"어, 내가 추측 한 문자셋이 무엇이든간에?"라고 말하는 것보다 다루고있는 문자셋 (예 :)을 알고 있음을 지정하도록 요구하는 것이 좋습니다. 많은 사람들에게 행복해 보입니다. 특히 Java는 UTF-8과 같은 의미있는 기본값을 사용하지 않기 때문입니다.
ColinD 2010

알아. 그래서 내 대답에서 UTF-8을 기본 버전으로 사용하고 있습니다.
Sean Patrick Floyd

또한 문서를 참조하십시오 : code.google.com/p/guava-libraries/wiki/IOExplained
바드

이 질문 :-) 질문을 받았다 때 그 문서가 존재하지 않았다 @Vadzim
숀 패트릭 플로이드

답변:


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합니다.

이것은 어떤 과부하 사실이없는 것을 제외하고 존 소총이 제안 정확히 무엇을 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);

요점은 InputSupplierGuava가 추악한 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, ByteSinkCharSink. 가 주어지면 ByteSource이제 다음 String과 같은 내용을 얻을 수 있습니다 .

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

훌륭한 정보 (+1)에 감사드립니다. 그러나 이것은 매우 장황합니다. 받아 들여진 대답을 Closeables.closeQuietly ()와 결합하는 것이 더 쉽다고 생각합니다.
Sean Patrick Floyd

@CollinD : 내 대답 중 하나에서 귀하의 방법을 사용했습니다. 코드를 살펴보고 이것이 InputSupplier를 사용하는 올바른 방법인지 알려주십시오.
Emil

1
@ColinD, inputStream이 doPost 서블릿 내부에서 오는 경우 닫는 데 어떤 의미가 있습니까? (또는 닫는 것에 대해 걱정)
Blankman

CharStreams.toString (InputSupplier)는 이제 더 이상 사용되지 않습니다. asCharSource를 사용하여 ByteSource에서 CharSource를 만든 다음 문서에서 제안한대로 toString을 사용했습니다.
John Lehmann 2014

4
TedM.Young @ : 당신은 모든이 경우 InputStream, 당신은으로 싶어 String, CharStreams.toString(new InputStreamReader(inputStream, charset))가는 방법이다. ByteSource그리고 CharSource당신의 소스 역할을 할 수있는 무언가가 경우에 특별히 있습니다 InputStreams 또는 ReaderS를.
ColinD

56

당신이 가지고있는 경우에 Readable당신은 사용할 수 있습니다 CharStreams.toString(Readable). 따라서 다음을 수행 할 수 있습니다.

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

어쨌든 당신이해야 할 문자 세트를 지정하도록 강요합니다.


4
실제로, 저는 귀하와 Jon Skeet의 답변을 조합하여 사용할 것입니다 :`CharStreams.toString (new InputStreamReader (supplier.get (), Charsets.UTF_8))`
Sean Patrick Floyd

네, 옵션을 결합하는 많은 방법이 있습니다!
Calum

10
@SPFloyd : 당신이이 있다면 InputSupplier<InputStream>난 강력하게 사용하는 것이 좋습니다 것 CharStreams.newReaderSupplier(supplier, Charsets.UTF_8)보다는 new InputStreamReader. 그 이유는 InputStreamReader, toString가 주어지면 닫지 않기 때문 입니다 Reader(따라서 기본 스트림이 아닙니다!). 사용하여 InputSupplier에 대한을 ReadertoString방법은 폐쇄 처리 할 Reader당신을 위해.
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;
    }
};

Jon, request.getInputStream을 통한 스트림입니까? 또한 @Calum의 답변에 언급 된 ColinD처럼 스트림을 닫을 수 있습니까?
Blankman

아, 그리고 서블릿 doPost 환경입니다. 어쨌든 스트림을 닫아야합니까?
Blankman

@Blankman : 아, 그것이 당신의 맥락입니다-당신의 질문에서 전혀 명확하지 않았습니다. 요청 스트림을 닫는 지 여부는 크게 중요하지 않지만 일반적으로 그렇게합니다. 나는이 대답을 편집 할 것입니다-그런 과부하가없는 것 같습니다.
Jon Skeet

1
나는 지금 이것을하고있다 : String payLoad = CharStreams.toString (new InputStreamReader (request.getInputStream (), "UTF-8"));
Blankman

1
@BeeOnRope : 한 가지 중간 접근 방식은 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에 따르면 스트림을 닫지 않습니다.
The Alchemist

사실입니다. 스트림을 닫는 Guava의 기능을 본 적이 없습니다. 글쎄, 가까운 것을 제외하고 조용히.
ponomandr

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

나에게 꽤 괜찮아 보인다. Guava의 IO 항목은 1 샷 스트림 및 리더 (가능한 경우)가 아닌 재사용 가능한 입력 공급자 측면에서 생각하는 법을 배우면 가장 잘 작동하지만 큰 변화가 될 기존 IOUtils 코드를 변환하고 있기 때문에 추측합니다.
ColinD 2010

2
내 구아바 14에서 closeQuietly는 이미 사용되지 않습니다. 제안 사항은 Java 7에있는 try-with-resources 기능을 사용하는 것입니다. 자세한 내용은 code.google.com/p/guava-libraries/wiki/…
bertie

2
@AlbertKam이 동의했습니다. 하지만 기억하세요 :이 답변은 3 년 전입니다.
Sean Patrick Floyd

@SeanPatrickFloyd : 감사합니다! 사실 나는 당신의 대답에서 시작하여 새로운 솔루션을 얻었습니다. 최신 버전을 사용하고있을 수있는 다른 사람들을 위해 댓글을 추가 할 생각이었습니다. :)
버티

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

1
대신 github.com/square/okio를 사용 해보세요. 한동안 Guava의 I / O를 사용하지 않았습니다. Okio가 더 좋습니다.
orip

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.