Java에서 InputStream을 읽고 문자열로 변환하는 방법은 무엇입니까?


4063

java.io.InputStream객체 가있는 경우 해당 객체를 어떻게 처리하고 String?


InputStream텍스트 데이터가 포함되어 있고이를로 변환하려고 한다고 가정하면 이 String를 예를 들어 로그 파일에 쓸 수 있습니다.

를 가져 와서 InputStream변환 하는 가장 쉬운 방법은 무엇입니까 String?

public String convertStreamToString(InputStream is) {
    // ???
}

36
이 질문에 대한 답변은 스트림의 내용을 완전히 읽으려는 경우에만 작동합니다 (닫을 때까지). 이것이 항상 의도 된 것은 아니기 때문에 (keep-alive 연결이있는 http 요청은 닫히지 않습니다),이 메소드는 블록을 호출합니다 (내용을 제공하지 않음).
f1sh

21
당신이 필요로 알고 스트림의 문자 인코딩을 지정하거나 합니다 사용되기 때문에, 문자 인코딩 버그가 임의로 기계 / 운영 체제 / 플랫폼 또는 버전이 그 코드가 실행되는에 따라 인코딩 선택. 즉 , 플랫폼 기본 인코딩에 의존하는 메소드를 사용 하지 마십시오 .
Christoffer Hammarström

11
9 년 전의 내 의견으로 재미있게하기 위해 요즘 Groovy의 "String s = new File ("SomeFile.txt "). text"을 사용하여 전체 파일을 한 번에 읽고 훌륭하게 작동합니다. 나는 비 프로덕션 (스크립트) 코드에 groovy를 사용하는 것을 기쁘게 생각합니다. 정말로 자바가하는 방식으로 인코딩 및 매우 긴 파일을 처리하도록 강요하면 Java가 생산 코드에 정말 좋은 아이디어이므로 목적에 맞게 작동합니다. Groovy는 자바가별로 빠르지 않은 빠른 스크립트에서 작동합니다. 작업에 적합한 도구 만 사용하면됩니다.
Bill K

ByteArrayOutputStream outputBytes = new ByteArrayOutputStream(); for(byte[] b = new byte[512]; 0 < inputStream.read(b); outputBytes.write(b)); return new String(outputBytes.toByteArray(), StandardCharsets.UTF_8);
Felypp Oliveira

Java 11에서 @BillK를 사용 String s = Files.readString​(Path.of("SomeFile.txt"));하면 언어가 얻을 수있는만큼 좋은 것을 사용할 수 있으며 설명 한 것과 같은 마법 유형 변환을 지원하지 않습니다.
Holger

답변:


2530

이 작업을 수행하는 좋은 방법은 사용하는 아파치 평민을 IOUtils 을 복사 InputStreamStringWriter같은 ... 뭔가

StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, encoding);
String theString = writer.toString();

또는

// NB: does not close inputStream, you'll have to use try-with-resources for that
String theString = IOUtils.toString(inputStream, encoding); 

또는 ByteArrayOutputStream스트림과 작가를 혼합하지 않으려는 경우 사용할 수 있습니다


75
안드로이드 개발자의 경우 안드로이드가 Apache의 IOUtils와 함께 제공되지 않는 것 같습니다. 따라서 다른 답변을 참조하는 것이 좋습니다.
Chris.Zou

47
이 시점에서 이것은 매우 오래된 질문입니다 (2008 년에 요청되었습니다). 보다 현대적인 답변을 읽는 것이 좋습니다. 일부는 Java 8 라이브러리에서 기본 호출을 사용합니다.
Shadoninja

36
이 답변은 매우 구식이며 그렇게 표시 할 수 있어야합니다 (슬프게도 가능하지 않습니다 atm).
codepleb

7
IOUtils.toString ()은 더 이상 사용되지 않습니다. 이 답변은 더 이상 권장되지 않습니다.
Roshan

7
그런 다음 편집 하여 향후 독자에게 도움이되는 이유를 설명합니다.
장 프랑수아 파브르

2486

이 작업을 수행하는 11 가지 주요 방법을 찾은 다른 답변을 요약하십시오 (아래 참조). 그리고 몇 가지 성능 테스트를 작성했습니다 (아래 결과 참조).

InputStream을 문자열로 변환하는 방법 :

  1. 사용 IOUtils.toString(아파치의 Utils)

    String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
  2. 사용 CharStreams(구아바)

    String result = CharStreams.toString(new InputStreamReader(
          inputStream, Charsets.UTF_8));
  3. 사용 Scanner(JDK)

    Scanner s = new Scanner(inputStream).useDelimiter("\\A");
    String result = s.hasNext() ? s.next() : "";
  4. Stream API 사용 (Java 8) 경고 :이 솔루션 변환 다른 줄 바꿈 (같은 \r\n)에 \n.

    String result = new BufferedReader(new InputStreamReader(inputStream))
      .lines().collect(Collectors.joining("\n"));
  5. 사용하여 병렬 스트림 API (자바 8). 경고 :이 솔루션 변환 다른 줄 바꿈 (같은 \r\n)에 \n.

    String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
       .parallel().collect(Collectors.joining("\n"));
  6. 사용 InputStreamReaderStringBuilder(JDK)

    final int bufferSize = 1024;
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    Reader in = new InputStreamReader(stream, StandardCharsets.UTF_8);
    int charsRead;
    while((charsRead = in.read(buffer, 0, buffer.length)) > 0) {
        out.append(buffer, 0, charsRead);
    }
    return out.toString();
  7. 사용 StringWriterIOUtils.copy(Apache Commons)

    StringWriter writer = new StringWriter();
    IOUtils.copy(inputStream, writer, "UTF-8");
    return writer.toString();
  8. 사용 ByteArrayOutputStreaminputStream.read(JDK)

    ByteArrayOutputStream result = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length;
    while ((length = inputStream.read(buffer)) != -1) {
        result.write(buffer, 0, length);
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    return result.toString("UTF-8");
  9. BufferedReader(JDK) 사용 경고 : 이 솔루션은 다른 줄 바꿈 (예 :) \n\rline.separator시스템 속성 (예 : Windows의 경우 "\ r \ n")으로 변환합니다.

    String newLine = System.getProperty("line.separator");
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    StringBuilder result = new StringBuilder();
    boolean flag = false;
    for (String line; (line = reader.readLine()) != null; ) {
        result.append(flag? newLine: "").append(line);
        flag = true;
    }
    return result.toString();
  10. 사용 BufferedInputStreamByteArrayOutputStream(JDK)

    BufferedInputStream bis = new BufferedInputStream(inputStream);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result != -1) {
        buf.write((byte) result);
        result = bis.read();
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    return buf.toString("UTF-8");
  11. 사용 inputStream.read()StringBuilder(JDK). 경고 :이 솔루션은 러시아어 텍스트와 같이 유니 코드에 문제가 있습니다 (유니 코드가 아닌 텍스트에서만 올바르게 작동 함)

    int ch;
    StringBuilder sb = new StringBuilder();
    while((ch = inputStream.read()) != -1)
        sb.append((char)ch);
    reset();
    return sb.toString();

경고 :

  1. 솔루션 4, 5 및 9는 다른 줄 바꿈을 하나로 변환합니다.

  2. 솔루션 11은 유니 코드 텍스트에서 올바르게 작동하지 않습니다

성능 테스트

작은 String(길이 = 175), github의 url에 대한 성능 테스트 (모드 = 평균 시간, 시스템 = Linux, 점수 1,343이 가장 좋음) :

              Benchmark                         Mode  Cnt   Score   Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   1,343 ± 0,028  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   6,980 ± 0,404  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   7,437 ± 0,735  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10   8,977 ± 0,328  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10  10,613 ± 0,599  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10  10,605 ± 0,527  us/op
 3. Scanner (JDK)                               avgt   10  12,083 ± 0,293  us/op
 2. CharStreams (guava)                         avgt   10  12,999 ± 0,514  us/op
 4. Stream Api (Java 8)                         avgt   10  15,811 ± 0,605  us/op
 9. BufferedReader (JDK)                        avgt   10  16,038 ± 0,711  us/op
 5. parallel Stream Api (Java 8)                avgt   10  21,544 ± 0,583  us/op

big String(길이 = 50100), github의 url에 대한 성능 테스트 (모드 = 평균 시간, 시스템 = Linux, 점수 200,715가 가장 좋음) :

               Benchmark                        Mode  Cnt   Score        Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   200,715 ±   18,103  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10   300,019 ±    8,751  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   347,616 ±  130,348  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10   352,791 ±  105,337  us/op
 2. CharStreams (guava)                         avgt   10   420,137 ±   59,877  us/op
 9. BufferedReader (JDK)                        avgt   10   632,028 ±   17,002  us/op
 5. parallel Stream Api (Java 8)                avgt   10   662,999 ±   46,199  us/op
 4. Stream Api (Java 8)                         avgt   10   701,269 ±   82,296  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   740,837 ±    5,613  us/op
 3. Scanner (JDK)                               avgt   10   751,417 ±   62,026  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10  2919,350 ± 1101,942  us/op

그래프 (Windows 7 시스템의 입력 스트림 길이에 따른 성능 테스트)
여기에 이미지 설명을 입력하십시오

Windows 7 시스템의 입력 스트림 길이에 따른 성능 테스트 (평균 시간) :

 length  182    546     1092    3276    9828    29484   58968

 test8  0.38    0.938   1.868   4.448   13.412  36.459  72.708
 test4  2.362   3.609   5.573   12.769  40.74   81.415  159.864
 test5  3.881   5.075   6.904   14.123  50.258  129.937 166.162
 test9  2.237   3.493   5.422   11.977  45.98   89.336  177.39
 test6  1.261   2.12    4.38    10.698  31.821  86.106  186.636
 test7  1.601   2.391   3.646   8.367   38.196  110.221 211.016
 test1  1.529   2.381   3.527   8.411   40.551  105.16  212.573
 test3  3.035   3.934   8.606   20.858  61.571  118.744 235.428
 test2  3.136   6.238   10.508  33.48   43.532  118.044 239.481
 test10 1.593   4.736   7.527   20.557  59.856  162.907 323.147
 test11 3.913   11.506  23.26   68.644  207.591 600.444 1211.545

17
당신이 "요약 대답"을 쓰고있어, 당신은 어떤 솔루션이 자동으로 (같은 다른 바꿈 변환 있음을 유의 \r\n으로) \n하는 경우에 바람직하지 않은 될 수 있습니다. 또한 필요한 추가 메모리 또는 최소한 할당 압력을 확인하는 것이 좋습니다 (적어도 JMH를 사용하여 실행할 수 있음 -prof gc). 정말 멋진 게시물의 경우 그래프를 보는 것이 좋습니다 (같은 입력 크기 내의 문자열 길이와 같은 문자열 길이 내의 입력 크기에 따라 다름).
Tagir Valeev

16
공감; 가장 재미있는 것은 결과가 예상보다 높다는 것입니다. 표준 JDK 및 / 또는 Apache Commons 구문 설탕을 사용해야합니다.
Aleksei Matiushkin

25
놀라운 소식. 단 하나. Java 8은 (이 입력 스트림과 같이) 잠그고 대기 해야하는 리소스에 병렬 스트림을 사용하지 않도록 경고하므로 병렬 스트림 옵션은 번거롭고 가치가 없습니다.
mangusbrother

10
병렬 스트림이 실제로 라인 순서를 유지합니까?
Natix

6
reset()예제 11의 내용은 무엇입니까 ?
Rob Stewart

2307

표준 Java 라이브러리 만 사용하는 방법이 있습니다 (스트림은 닫히지 않으며 마일리지는 다를 수 있습니다).

static String convertStreamToString(java.io.InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}

"Stupid Scanner tricks" 기사 에서이 트릭을 배웠습니다 . 이것이 작동하는 이유는 스캐너 가 스트림의 토큰을 반복 하기 때문에 "입력 경계의 시작"(\ A)을 사용하여 토큰을 분리하여 스트림의 전체 내용에 대해 하나의 토큰 만 제공하기 때문입니다.

입력 스트림의 인코딩에 대해 구체적이어야 Scanner하는 경우 사용할 문자 세트 (예 : "UTF-8")를 나타내는 두 번째 인수를 생성자에 제공 할 수 있습니다 .

모자 팁도 야곱 에게 갔다.


8
고맙습니다.이 버전의 경우 입력 스트림을 닫는 finally 블록을 추가 했으므로 입력을 읽은 후 사용자가 필요하지 않습니다. 발신자 코드를 상당히 단순화합니다.

4
필자의 경우 @PavelRepin @Patrick, 스캐너 입력 중에 빈 inputStream으로 인해 NPE가 발생했습니다. if (is == null) return "";방법의 시작 부분에 바로 추가해야 했습니다. null 입력 스트림을보다 잘 처리하려면이 답변을 업데이트해야한다고 생각합니다.
CFL_Jeff

115
Java 7의 경우 다음과 같이 사용해 볼 수 있습니다. try(java.util.Scanner s = new java.util.Scanner(is)) { return s.useDelimiter("\\A").hasNext() ? s.next() : ""; }
earcam

5
불행히도이 솔루션은 기본 스트림 구현에서 발생하는 예외를 잃어 버린 것 같습니다.
Taig

11
참고 로 콘솔 입력 스트림의 hasNext 블록입니다 ( 여기 참조 ). (지금 막이 문제에 부딪 쳤습니다.)이 솔루션은 그렇지 않으면 잘 작동합니다.
Ryan

848

Apache Commons는 다음을 허용합니다.

String myString = IOUtils.toString(myInputStream, "UTF-8");

물론 UTF-8 이외의 다른 문자 인코딩을 선택할 수도 있습니다.

참조 : ( documentation )


1
또한 기본 인코딩으로 찾은 경우 inputStream 인수 만 사용하는 메소드가 있습니다.

13
@Guillaume Coté 여기에서 메시지는 자바 코드가 실행되는 플랫폼에 따라 그것이 무엇인지 확신 할 수 없기 때문에 "기본 인코딩으로 정밀하지 않아야"한다는 것입니다.
Per Wiklander

7
@Per Wiklander 동의하지 않습니다. 단일 코드에서 작동하는 코드는 기본 인코딩이 잘 될 것입니다. 로컬 파일 만 여는 코드의 경우 플랫폼 기본 인코딩으로 인코딩하도록 요청하는 것이 합당한 옵션입니다.
기 illa 코트

39
Googling의 번거 로움을 없애려면 <dependency> <groupId> org.apache.commons </ groupId> <artifactId> commons-io </ artifactId> <version> 1.3.2 </ version> </ dependency>
Chris

7
또한 일반 문자열 리터럴을 사용하는 대신 문자 인코딩에 Apache 상수 (또는 다른) 상수를 사용하는 것도 거의 개선되지 않습니다. 예 : IOUtils.toString (myInputStream, Charsets.UTF_8);

300

파일을 고려하면 먼저 java.io.Reader인스턴스를 가져와야합니다. 그런 다음 이것을 읽고 추가 할 수 있습니다 StringBuilder( StringBuffer여러 스레드에서 액세스하지 않으면 StringBuilder더 빠를 필요 가 없습니다 ). 여기서 트릭은 블록 단위로 작업하므로 다른 버퍼링 스트림이 필요하지 않다는 것입니다. 블록 크기는 런타임 성능 최적화를 위해 매개 변수화됩니다.

public static String slurp(final InputStream is, final int bufferSize) {
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    try (Reader in = new InputStreamReader(is, "UTF-8")) {
        for (;;) {
            int rsz = in.read(buffer, 0, buffer.length);
            if (rsz < 0)
                break;
            out.append(buffer, 0, rsz);
        }
    }
    catch (UnsupportedEncodingException ex) {
        /* ... */
    }
    catch (IOException ex) {
        /* ... */
    }
    return out.toString();
}

8
이 솔루션은 멀티 바이트 문자를 사용합니다. 이 예에서는 전체 유니 코드 범위 (중국어 포함)를 표현할 수있는 UTF-8 인코딩을 사용합니다. "UTF-8"을 다른 인코딩으로 바꾸면 해당 인코딩을 사용할 수 있습니다.
Paul de Vrieze

27
@ User1-코드에서 라이브러리를 사용하여 작업을 더 빨리 수행 할 수 있습니다. 관리자들이 "와우 제임스! 어떻게 그렇게 빨리 했습니까?!"라고 말하면 정말 좋습니다. 그러나 우리가 공통적이고 재사용 가능하며 시험을 거친 유틸리티를 포함하는 것에 대한 아이디어를 잘못 놓아서 바퀴를 재발 명하는 데 시간을 할애해야 할 때 프로젝트 목표를 달성하는 데 소비 할 수있는 시간을 포기하게됩니다. 우리가 바퀴를 재발 명할 때, 우리는 두 배나 열심히 일하지만 훨씬 나중에 결승선에 도달합니다. 결승선에 도착하면 축하 할 사람이 없습니다. 집을 지을 때 망치도 짓지 마십시오
jmort253

10
죄송합니다. 내 의견을 다시 읽은 후 조금 오만한 것입니다. 나는 단지 라이브러리를 피해야 할 좋은 이유가 있고 그 이유가 유효한 이유라고 생각합니다. :)
jmort253

4
@ jmort253 우리는 제품의 일부 라이브러리를 여러 번 업데이트 한 후 성능 회귀를 발견했습니다. 운 좋게도 우리는 소위 마감일을 갖지 않도록 자체 제품을 제작하고 판매하고 있습니다. 불행히도 우리는 많은 운영 체제의 많은 JVM, 데이터베이스 및 응용 프로그램 서버에서 사용할 수있는 제품을 구축하므로 열악한 시스템을 사용하는 사용자를 고려해야합니다 ... 그리고 문자열 작업 최적화는 성능을 30 ~ 40 % 향상시킬 수 있습니다. 그리고 수정 : In our product, I even replaced'우리는 심지어 교체해야합니다'.
coolcfan

10
@ jmort253 이미 아파치 커먼즈를 사용하고 있다면 가십시오. 동시에, 많은 아파치 자바 라이브러리에서 의존성 확산이 보여주는 것처럼 라이브러리를 사용하는 데 실제 비용이 있습니다. 이것이 라이브러리를 유일하게 사용하는 경우 라이브러리를 사용하는 것은 과잉입니다. 반면, 자체 버퍼 크기를 결정하면 메모리 / 프로세서 사용 균형을 조정할 수 있습니다.
Paul de Vrieze

248

사용하다:

InputStream in = /* Your InputStream */;
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String read;

while ((read=br.readLine()) != null) {
    //System.out.println(read);
    sb.append(read);
}

br.close();
return sb.toString();

11
문제는 먼저 줄로 나눈 다음 실행 취소하는 것입니다. 임의 버퍼를 읽는 것이 더 쉽고 빠릅니다.
Paul de Vrieze

20
또한 readLine은 \ n과 \ r을 구분하지 않으므로 정확한 스트림을 다시 재생할 수 없습니다.
마리아 아리아스 드 레이나 Domínguez

2
readLineEOL을 찾기 위해 문자별로 읽을 때 매우 비효율적 입니다. 또한 스트림에 줄 바꿈이 없으면 실제로 의미가 없습니다.
njzk2

3
@Gops AB : 이것을 시도하고 샘플에 줄 바꿈이 있으면 readline ()을 사용 하여이 루프가 구성되는 방식과 StringBuilder.append ()가 실제로 줄 바꿈을 유지하지 않는다는 것을 알 수 있습니다.
Russ Bateman

4
바이트 단위의 바이트가 아니기 때문에 이것이 가장 좋은 대답은 아닙니다. 독자는 줄 바꿈을 방해하므로 유지 관리에 신중해야합니다.
Jeffrey Blattman

173

Google 컬렉션 / 구아바를 사용하는 경우 다음을 수행 할 수 있습니다.

InputStream stream = ...
String content = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
Closeables.closeQuietly(stream);

에 대한 두 번째 매개 변수 (예 : Charsets.UTF_8) InputStreamReader는 필요하지 않지만 일반적으로 인코딩을 알고 있으면이를 지정하는 것이 좋습니다.


2
@harschware : "java.io.InputStream 객체를 가지고 있다면 어떻게 그 객체를 처리하고 문자열을 생성해야합니까?"라는 질문이 주어졌습니다. 상황에 이미 스트림이 있다고 가정했습니다.
사쿠라바

당신은 당신의 대답을 잘 설명하지 않았으며, 외부 변수가있었습니다. user359996은 귀하와 동일한 내용이지만 훨씬 더 명확하게 말했습니다.
Uronym

2
구아바의 경우 +1, 입력 스트림의 인코딩을 지정하지 않은 경우 -1 예. 새로운 InputStreamReader (stream, "UTF-8")
andras

@Chris Noldus 반면에, 일부 사람들은 이미 나와 같은 프로젝트에 구아바를 가지고 있으며이 솔루션이 SDK 전용 버전보다 더 우아하다고 생각합니다.
CorayThan

@Vadzim 대답은 이것과 동일합니다-둘 다 CharStreams.toString을 사용하십시오
Tom

125

이것은 Android 및 기타 JVM에 완벽하게 맞는 최상의 순수 Java 솔루션입니다.

이 솔루션은 놀랍도록 잘 작동합니다 ... 간단하고 빠르며 크고 작은 스트림에서도 동일하게 작동합니다 !! (위의 벤치 마크 참조. No. 8 )

public String readFullyAsString(InputStream inputStream, String encoding)
        throws IOException {
    return readFully(inputStream).toString(encoding);
}

public byte[] readFullyAsBytes(InputStream inputStream)
        throws IOException {
    return readFully(inputStream).toByteArray();
}

private ByteArrayOutputStream readFully(InputStream inputStream)
        throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length = 0;
    while ((length = inputStream.read(buffer)) != -1) {
        baos.write(buffer, 0, length);
    }
    return baos;
}

4
엔터프라이즈 자바에서만 작동하는 다른 답변과 비교하여 Android에서 잘 작동합니다.
vortexwolf

짧은 문자열에 대해 ".write"줄에서 OutOfMemory 오류가 발생하여 Android에서 충돌이 발생했습니다.
Adam

인코딩을 추가했습니다. 부수적으로, 내 코드에있는 원래 readFully 메소드는 String을 반환하지 않으며보다 일반적인 기능을 위해 byte []를 반환합니다. 인코딩을 사용하여 새로운 String (...)을 구현하는 것은 API를 사용하는 on의 책임입니다!
TacB0sS

2
빠른 참고 :이 메모리 사용량은 최대이며 2*n, 여기서 ByteArrayInputStream자동 증가 시스템 에 따라 n은 스트림 크기입니다 .
njzk2

3
불필요하게 메모리 사용을 두 배로 늘리는 것은 모바일 장치에서 중요합니다. InputStreamReader를 사용하고 StringReader에 추가하는 것이 좋습니다. 바이트에서 문자로의 변환은 대량으로 끝나지 않고 즉시 수행됩니다.
Oliv

84

완전성을 위해 여기에 Java 9 솔루션이 있습니다.

public static String toString(InputStream input) throws IOException {
    return new String(input.readAllBytes(), StandardCharsets.UTF_8);
}

readAllBytes그 가능성이 출시에 표시 할 수 있도록, JDK 9 주요 코드베이스에 현재이다. JDK 9 스냅 샷 빌드를 사용하여 지금 시도해 볼 수 있습니다 .


이 메소드는 읽기 위해 많은 양의 메모리를 할당하지 않습니까? byte[] buf = new byte[DEFAULT_BUFFER_SIZE];어디에서 MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;제공합니다 MAX_BUFFER_SIZE = 2147483639. 구글은 약 2.147GB라고 말합니다.
Rekin

죄송합니다. 계산에 오류가 있습니다. 2GB입니다. 댓글을 편집했습니다. 따라서 4kb 파일처럼 읽더라도 2GB의 메모리를 사용합니까?
Rekin

2
@ChristianHujer, 최신 jdk8u commit 에서 볼 수 없습니다 . AFAIK의 새로운 방법은 Java 업데이트에 도입되지 않았으며 주요 릴리스에만 도입되었습니다.
Tagir Valeev

4
@ChristianHujer, 질문은에 대한 것이 InputStream아니라에 대한 것이 었습니다 Path. 는 InputStream다양한 소스에서 생성 할 수 있습니다, 파일 만하지.
Tagir Valeev

5
이것은 1 년 전에 작성되었으므로 업데이트하기 위해이 방법이 공개 릴리스 JDK 9에서 실제로 있음을 확인했습니다. 또한 인코딩이 "ISO-Latin-1"이면 Java 9 Strings가 이제 사용되므로 매우 효율적입니다. byte[]구현 모든 문자는 첫 번째 256 개 코드 포인트에있는 경우. 이것은 새로운 String (byte [], "ISO-Latin-1")이 간단한 배열 복사가됨을 의미합니다.
Klitos Kyriacou

66

사용하다:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;

public static String readInputStreamAsString(InputStream in)
    throws IOException {

    BufferedInputStream bis = new BufferedInputStream(in);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result != -1) {
      byte b = (byte)result;
      buf.write(b);
      result = bis.read();
    }
    return buf.toString();
}

@ DanielDeLeón 아닙니다. 그것은이다 BufferedInputStream. 기본 읽기는 한 번에 8192 바이트입니다.
user207421

2
@ EJP 나는 한 번에 1 바이트 대신 바이트 배열 버퍼를 사용 BufferedInputStream 하고 읽는 것보다 속도가 느리다는 것을 알았습니다 . 예 : 4.56 MiB 파일을 읽을 때 200ms 대 60ms
jk7

아무도 여기에서 다른 주요 문제를 지적하지 않았을 가능성이 있습니다 (예 : 바이트 단위로 콘텐츠를 읽는 것은 버퍼링을하더라도 낭비입니다) : "기본 인코딩"에 발생하는 모든 것에 의존합니다. 이것은 거의 좋은 방법이 아닙니다. 대신에 인코딩을 인수로 전달해야 buf.toString()합니다.
StaxMan

@ jk7 4.56MB 파일을 읽는 시간이 너무 작아서 차이가 크지 않을 수 있습니다.
user207421

63

다음은 실험 후 얻은 가장 우아하고 순수한 Java (라이브러리 없음) 솔루션입니다.

public static String fromStream(InputStream in) throws IOException
{
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    StringBuilder out = new StringBuilder();
    String newLine = System.getProperty("line.separator");
    String line;
    while ((line = reader.readLine()) != null) {
        out.append(line);
        out.append(newLine);
    }
    return out.toString();
}

8
@TorbenKohlmeier, 리더 및 버퍼는 닫을 필요가 없습니다. 제공자 InputStream는 발신자가 닫아야합니다.
Drew Noake 님이

7
CharSet을 사용하는 InputStreamReader에 더 바람직한 생성자가 있다는 것을 잊지 마십시오.
jontejj

7
사람들은 왜 계속 사용 readLine합니까? 당신은 그 자체로 선을 사용하지 않는 경우, (매우 느린 것을 제외?)을 어떤 좋은
njzk2

4
한 줄씩 읽지 마십시오. 한 줄이 너무 길어서 힙에 맞지 않으면 어떻게됩니까?
voho

4
@voho, 한 줄이 길면 그 줄과 크기가 같아야하는 반환 값을 할당 할 수있는 방법이 없습니다. 큰 파일을 처리하는 경우 파일을 스트리밍해야합니다. 작은 텍스트 파일을 메모리에로드하는 데는 많은 사용 사례가 있습니다.
Drew Noakes

55

나는 여기에 14 개의 별개의 답변에 대한 벤치 마크를했습니다 (크레딧을 제공하지 못했지만 중복이 너무 많습니다).

결과는 매우 놀랍습니다. Apache IOUtils 가 가장 느리고ByteArrayOutputStream 가장 빠른 솔루션 .

먼저 여기에 가장 좋은 방법이 있습니다.

public String inputStreamToString(InputStream inputStream) throws IOException {
    try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }

        return result.toString(UTF_8);
    }
}

20주기 동안 20MB 임의 바이트의 벤치 마크 결과

밀리 초 단위의 시간

  • ByteArrayOutputStream 테스트 : 194
  • NioStream : 198
  • 전송 대상 : 201
  • Java9ISReadAllBytes : 205
  • BufferedInputStreamVsByteArrayOutputStream : 314
  • ApacheStringWriter2 : 574
  • 구아바
  • 스캐너 리더 다음 테스트 : 614
  • 스캐너 리더 : 633
  • ApacheStringWriter : 1544
  • StreamApi : 오류
  • ParallelStreamApi : 오류
  • BufferReaderTest : 오류
  • InputStreamAndStringBuilder : 오류

벤치 마크 소스 코드

import com.google.common.io.CharStreams;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * Created by Ilya Gazman on 2/13/18.
 */
public class InputStreamToString {


    private static final String UTF_8 = "UTF-8";

    public static void main(String... args) {
        log("App started");
        byte[] bytes = new byte[1024 * 1024];
        new Random().nextBytes(bytes);
        log("Stream is ready\n");

        try {
            test(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void test(byte[] bytes) throws IOException {
        List<Stringify> tests = Arrays.asList(
                new ApacheStringWriter(),
                new ApacheStringWriter2(),
                new NioStream(),
                new ScannerReader(),
                new ScannerReaderNoNextTest(),
                new GuavaCharStreams(),
                new StreamApi(),
                new ParallelStreamApi(),
                new ByteArrayOutputStreamTest(),
                new BufferReaderTest(),
                new BufferedInputStreamVsByteArrayOutputStream(),
                new InputStreamAndStringBuilder(),
                new Java9ISTransferTo(),
                new Java9ISReadAllBytes()
        );

        String solution = new String(bytes, "UTF-8");

        for (Stringify test : tests) {
            try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
                String s = test.inputStreamToString(inputStream);
                if (!s.equals(solution)) {
                    log(test.name() + ": Error");
                    continue;
                }
            }
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < 20; i++) {
                try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
                    test.inputStreamToString(inputStream);
                }
            }
            log(test.name() + ": " + (System.currentTimeMillis() - startTime));
        }
    }

    private static void log(String message) {
        System.out.println(message);
    }

    interface Stringify {
        String inputStreamToString(InputStream inputStream) throws IOException;

        default String name() {
            return this.getClass().getSimpleName();
        }
    }

    static class ApacheStringWriter implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            StringWriter writer = new StringWriter();
            IOUtils.copy(inputStream, writer, UTF_8);
            return writer.toString();
        }
    }

    static class ApacheStringWriter2 implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return IOUtils.toString(inputStream, UTF_8);
        }
    }

    static class NioStream implements Stringify {

        @Override
        public String inputStreamToString(InputStream in) throws IOException {
            ReadableByteChannel channel = Channels.newChannel(in);
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 16);
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            WritableByteChannel outChannel = Channels.newChannel(bout);
            while (channel.read(byteBuffer) > 0 || byteBuffer.position() > 0) {
                byteBuffer.flip();  //make buffer ready for write
                outChannel.write(byteBuffer);
                byteBuffer.compact(); //make buffer ready for reading
            }
            channel.close();
            outChannel.close();
            return bout.toString(UTF_8);
        }
    }

    static class ScannerReader implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
            return s.hasNext() ? s.next() : "";
        }
    }

    static class ScannerReaderNoNextTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
            return s.next();
        }
    }

    static class GuavaCharStreams implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            return CharStreams.toString(new InputStreamReader(
                    is, UTF_8));
        }
    }

    static class StreamApi implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new BufferedReader(new InputStreamReader(inputStream))
                    .lines().collect(Collectors.joining("\n"));
        }
    }

    static class ParallelStreamApi implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new BufferedReader(new InputStreamReader(inputStream)).lines()
                    .parallel().collect(Collectors.joining("\n"));
        }
    }

    static class ByteArrayOutputStreamTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = inputStream.read(buffer)) != -1) {
                    result.write(buffer, 0, length);
                }

                return result.toString(UTF_8);
            }
        }
    }

    static class BufferReaderTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            String newLine = System.getProperty("line.separator");
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder result = new StringBuilder(UTF_8);
            String line;
            boolean flag = false;
            while ((line = reader.readLine()) != null) {
                result.append(flag ? newLine : "").append(line);
                flag = true;
            }
            return result.toString();
        }
    }

    static class BufferedInputStreamVsByteArrayOutputStream implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            ByteArrayOutputStream buf = new ByteArrayOutputStream();
            int result = bis.read();
            while (result != -1) {
                buf.write((byte) result);
                result = bis.read();
            }

            return buf.toString(UTF_8);
        }
    }

    static class InputStreamAndStringBuilder implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            int ch;
            StringBuilder sb = new StringBuilder(UTF_8);
            while ((ch = inputStream.read()) != -1)
                sb.append((char) ch);
            return sb.toString();
        }
    }

    static class Java9ISTransferTo implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            inputStream.transferTo(bos);
            return bos.toString(UTF_8);
        }
    }

    static class Java9ISReadAllBytes implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new String(inputStream.readAllBytes(), UTF_8);
        }
    }

}

Java에서 벤치 마크를 만드는 것은 쉽지 않습니다 (특히 JIT로 인해). 벤치 마크 소스 코드를 읽은 후 위의 값이 정확하지 않으며 모든 사람이이를 믿고주의를 기울여야한다고 확신합니다.
달리 보

@Dalibor 당신은 아마도 링크가 아니라 주장에 대한 더 많은 추론을 제공해야 할 것입니다.
Ilya Gazman

나는 당신 자신의 벤치 마크를 만들기가 쉽지 않다는 것이 실제로 알려진 사실이라고 생각합니다. 그것을 모르는 사람들을 위해 링크가 있습니다.)
Dalibor

@Dalibor 아마도 최고는 아니지만 Java 벤치 마크를 잘 알고 있으므로 특정 문제를 지적 할 수 없다면 오해의 소지가 있으므로 그러한 조건에서 계속 대화하지 않을 것입니다.
Ilya Gazman

대부분 Dalibor에 동의합니다. 당신은 "자바 벤치 마크를 잘 이해하고있다"고 말하지만,이 접근 방식의 잘 알려진 문제를 분명히 모르면서 가장 순진한 접근 방식을 구현 한 것 같습니다. 우선,이 질문에 대한 모든 게시물을 읽으십시오 : stackoverflow.com/questions/504103/…
DavidS

41

Java 8 트릭을 사용합니다.

public static String streamToString(final InputStream inputStream) throws Exception {
    // buffering optional
    try
    (
        final BufferedReader br
           = new BufferedReader(new InputStreamReader(inputStream))
    ) {
        // parallel optional
        return br.lines().parallel().collect(Collectors.joining("\n"));
    } catch (final IOException e) {
        throw new RuntimeException(e);
        // whatever.
    }
}

더 간결한 것을 제외하고는 다른 답변과 본질적으로 동일합니다.


5
전화가 올까 return null? 중 하나를 br.lines...반환 또는 예외가 슬로우됩니다.
Holloway

3
@ Khaled A Khunaifer : 예, 확실히 ... 아마도 여기를 봐야합니다 : docs.oracle.com/javase/tutorial/essential/exceptions/… . 잘못 편집 한 것은 "자원을 사용하여 시도"문입니다.
jamp February

11
parallel()스트림 을 호출 합니까?
robinst

4
만약 소스 스트림이 윈도우 라인 엔딩을 사용한다면 데이터 가 정직하게 복사 되지는 않을 \r\n것이다 \n.
Lucas

2
System.lineSeparator()적절한 플랫폼 종속 줄 끝을 사용하는 데 사용할 수 있습니다 .
Steve K

34

시간이 항상 중요하기 때문에 타이밍 테스트를 실행했습니다.

String 3 다른 방법으로 응답을 얻으려고했습니다. (아래 그림 참조)
사케 가독성을 위해 try / catch 블록을 생략했습니다.

컨텍스트를 제공하기 위해 다음은 세 가지 접근 방식 모두에 대한 선행 코드입니다.

   String response;
   String url = "www.blah.com/path?key=value";
   GetMethod method = new GetMethod(url);
   int status = client.executeMethod(method);

1)

 response = method.getResponseBodyAsString();

2)

InputStream resp = method.getResponseBodyAsStream();
InputStreamReader is=new InputStreamReader(resp);
BufferedReader br=new BufferedReader(is);
String read = null;
StringBuffer sb = new StringBuffer();
while((read = br.readLine()) != null) {
    sb.append(read);
}
response = sb.toString();

삼)

InputStream iStream  = method.getResponseBodyAsStream();
StringWriter writer = new StringWriter();
IOUtils.copy(iStream, writer, "UTF-8");
response = writer.toString();

따라서 동일한 요청 / 응답 데이터를 사용하여 각 방법에 대해 500 개의 테스트를 실행 한 후 숫자가 있습니다. 다시 한 번, 이것들은 나의 발견이며 당신의 발견은 정확히 같지 않을 수도 있지만, 나는이 접근법의 효율성 차이를 다른 사람들에게 알리기 위해 이것을 썼습니다.

순위 :
접근법 # 1
접근법 # 3-# 1보다 2.6 % 느림
접근법 # 2-# 1보다 4.3 % 느림

이러한 접근 방법 중 하나는 응답을 잡고 그로부터 문자열을 작성하는 데 적합한 솔루션입니다.


2
2) 오류가 포함되어 있습니다. 항상 한 단계 더 필요한 단계를 수행하므로 문자열 끝에 항상 "널"을 추가합니다. 어쨌든 성능은 같습니다. 작동해야합니다. String read = null; StringBuffer sb = 새로운 StringBuffer (); while ((read = br.readLine ())! = null) {sb.append (read); }
LukeSolar

getMethod 메소드가 아니라 표준 자바 org.apache.commons.httpclient의 일부임을 주목해야한다
jk7가

파일 #에 줄이 많은 경우 접근법 # 2는 '\ n'을 소비합니다. 이것은 답이 아니어야합니다
Ninja

33

Stream 을 사용하는 순수 Java 솔루션 은 Java 8부터 작동합니다.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

// ...
public static String inputStreamToString(InputStream is) throws IOException {
    try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
        return br.lines().collect(Collectors.joining(System.lineSeparator()));
    }
}

Christoffer Hammarström이 다른 답변에서 언급했듯이 Charset 을 명시 적으로 지정하는 것이 더 안전합니다 . 즉, InputStreamReader 생성자는 다음과 같이 변경 될 수 있습니다.

new InputStreamReader(is, Charset.forName("UTF-8"))

11
대신 일의 Charset.forName("UTF-8")사용 StandardCharsets.UTF_8(에서 java.nio.charset).
robinst

26

다음은 다소간 sampath의 답변이며 약간 정리되어 함수로 표시됩니다.

String streamToString(InputStream in) throws IOException {
  StringBuilder out = new StringBuilder();
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  for(String line = br.readLine(); line != null; line = br.readLine()) 
    out.append(line);
  br.close();
  return out.toString();
}


21

Commons IO (FileUtils / IOUtils / CopyUtils)를 사용할 수없는 경우 다음은 BufferedReader를 사용하여 파일을 한 줄씩 읽는 예제입니다.

public class StringFromFile {
    public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
        InputStream is = StringFromFile.class.getResourceAsStream("file.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(is/*, "UTF-8"*/));
        final int CHARS_PER_PAGE = 5000; //counting spaces
        StringBuilder builder = new StringBuilder(CHARS_PER_PAGE);
        try {
            for(String line=br.readLine(); line!=null; line=br.readLine()) {
                builder.append(line);
                builder.append('\n');
            }
        } 
        catch (IOException ignore) { }

        String text = builder.toString();
        System.out.println(text);
    }
}

또는 원시 속도를 원한다면 Paul de Vrieze가 제안한 변형을 제안합니다 (StringWriter를 내부적으로 사용하지 않는 StringWriter 사용을 피함).

public class StringFromFileFast {
    public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
        InputStream is = StringFromFileFast.class.getResourceAsStream("file.txt");
        InputStreamReader input = new InputStreamReader(is/*, "UTF-8"*/);
        final int CHARS_PER_PAGE = 5000; //counting spaces
        final char[] buffer = new char[CHARS_PER_PAGE];
        StringBuilder output = new StringBuilder(CHARS_PER_PAGE);
        try {
            for(int read = input.read(buffer, 0, buffer.length);
                    read != -1;
                    read = input.read(buffer, 0, buffer.length)) {
                output.append(buffer, 0, read);
            }
        } catch (IOException ignore) { }

        String text = output.toString();
        System.out.println(text);
    }
}

코드를 작동시키기 위해 this.getClass (). getClassLoader (). getResourceAsStream ()을 사용해야했습니다 (maven 프로젝트에서 Eclipse 사용)
greuze

19

이것은 다음과 같은 이유로 좋습니다.

  • 문자셋을 안전하게 처리합니다.
  • 읽기 버퍼 크기를 제어합니다.
  • 빌더의 길이를 프로비저닝 할 수 있으며 정확한 값일 필요는 없습니다.
  • 라이브러리 종속성이 없습니다.
  • Java 7 이상입니다.

어떻게합니까?

public static String convertStreamToString(InputStream is) throws IOException {
   StringBuilder sb = new StringBuilder(2048); // Define a size if you have an idea of it.
   char[] read = new char[128]; // Your buffer size.
   try (InputStreamReader ir = new InputStreamReader(is, StandardCharsets.UTF_8)) {
     for (int i; -1 != (i = ir.read(read)); sb.append(read, 0, i));
   }
   return sb.toString();
}

JDK 9의 경우

public static String inputStreamString(InputStream inputStream) throws IOException {
    try (inputStream) {
        return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
    }
}

1
catch (Throwable)이 생산 코드의 경우 정말 비워 둘 수 없습니다합니다.
Christian Hujer

1
이 캐치-던질 수있는 진술에 무엇을 넣어야합니까?
alex

일반적으로 UTF-8을 사용하는 것이 합리적이지만 문자가 그렇게 인코딩 된 것으로 가정해서는 안됩니다.
마틴

18

이것은 아파치 구현을 원하지만 전체 라이브러리를 원하지 않는 사람들을 위해 org.apache.commons.io.IOUtils 소스 코드 에서 채택 된 답변 입니다.

private static final int BUFFER_SIZE = 4 * 1024;

public static String inputStreamToString(InputStream inputStream, String charsetName)
        throws IOException {
    StringBuilder builder = new StringBuilder();
    InputStreamReader reader = new InputStreamReader(inputStream, charsetName);
    char[] buffer = new char[BUFFER_SIZE];
    int length;
    while ((length = reader.read(buffer)) != -1) {
        builder.append(buffer, 0, length);
    }
    return builder.toString();
}

18

스트림 리더를 사용하는 경우 스트림을 종료해야합니다

private String readStream(InputStream iStream) throws IOException {
    //build a Stream Reader, it can read char by char
    InputStreamReader iStreamReader = new InputStreamReader(iStream);
    //build a buffered Reader, so that i can read whole line at once
    BufferedReader bReader = new BufferedReader(iStreamReader);
    String line = null;
    StringBuilder builder = new StringBuilder();
    while((line = bReader.readLine()) != null) {  //Read till end
        builder.append(line);
        builder.append("\n"); // append new line to preserve lines
    }
    bReader.close();         //close all opened stuff
    iStreamReader.close();
    //iStream.close(); //EDIT: Let the creator of the stream close it!
                       // some readers may auto close the inner stream
    return builder.toString();
}

편집 : JDK 7 이상에서는 try-with-resources 구문을 사용할 수 있습니다.

/**
 * Reads the stream into a string
 * @param iStream the input stream
 * @return the string read from the stream
 * @throws IOException when an IO error occurs
 */
private String readStream(InputStream iStream) throws IOException {

    //Buffered reader allows us to read line by line
    try (BufferedReader bReader =
                 new BufferedReader(new InputStreamReader(iStream))){
        StringBuilder builder = new StringBuilder();
        String line;
        while((line = bReader.readLine()) != null) {  //Read till end
            builder.append(line);
            builder.append("\n"); // append new line to preserve lines
        }
        return builder.toString();
    }
}

2
스트림을 닫는 것은 옳습니다. 그러나 스트림을 닫는 책임은 일반적으로 스트림 생성자 (시작한 것을 끝내는 것)에 있습니다. 따라서 iStream호출자가 생성했기 때문에 호출자가 실제로 닫아야합니다 iStream. 게다가, 스트림 닫기는 finally블록 단위 로 수행 되거나 Java 7 try-with-resources 문 에서 수행되어야합니다 . 코드에서 readLine()throws IOException또는 builder.append()throws OutOfMemoryError스트림은 열린 상태로 유지됩니다.
Christian Hujer

16

모든 Spring 사용자를위한 또 다른 하나 :

import java.nio.charset.StandardCharsets;
import org.springframework.util.FileCopyUtils;

public String convertStreamToString(InputStream is) throws IOException { 
    return new String(FileCopyUtils.copyToByteArray(is), StandardCharsets.UTF_8);
}

의 유틸리티 메소드는의 메소드 org.springframework.util.StreamUtils와 비슷 FileCopyUtils하지만 완료되면 스트림을 열린 상태로 둡니다.


16

사용 java.io.InputStream.transferTo (OutputStream에) 자바 (9)에서 지원하고 ByteArrayOutputStream.toString (문자열) 캐릭터 세트의 이름을 사용합니다 :

public static String gobble(InputStream in, String charsetName) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    in.transferTo(bos);
    return bos.toString(charsetName);
}

귀하의 경우에 문자셋 이름으로 무엇을 전달 했습니까?
virsha December

1
@virsha InputStream을 제공 한 소스에서이를 확인해야합니다. 기억 그것을 사용하는 인코딩 모르고 의미가 문자열을 가지고하지 않습니다.
jmehrens

15

여기에 변환하는 완벽한 방법 InputStream으로 String제 3 자 라이브러리를 사용하지 않고는. 를 사용하여 StringBuilder단일 스레드 환경 그렇지 않으면 사용 StringBuffer.

public static String getString( InputStream is) throws IOException {
    int ch;
    StringBuilder sb = new StringBuilder();
    while((ch = is.read()) != -1)
        sb.append((char)ch);
    return sb.toString();
}

3
이 방법에는 적용된 인코딩이 없습니다. 따라서 InputStream에서 수신 한 데이터가 UTF-8을 사용하여 인코딩되어 출력이 잘못되었다고 가정 해 봅시다. 이 문제를 해결하려면 in = new InputStreamReader(inputStream)및을 사용할 수 있습니다 (char)in.read().
Frederic Leitenberger

2
메모리 비효율적이다; 나는 큰 입력을하기 전에이 사용하여 시도하고 모두 StringBuilder는 메모리가 부족 생각
gengkev

1
char [] 버퍼를 사용하고보다 효율적이며 charset을 처리하는 또 다른 비슷한 대답이 있습니다.
기 illa 페로

14

바이트 배열 버퍼를 사용하는 JDK 만 사용하는 방법은 다음과 같습니다. 이것이 실제로 commons-io IOUtils.copy()메소드가 모두 작동하는 방식입니다. 당신은 대체 할 수 byte[]와 함께 char[]당신이에서 복사하는 경우 Reader대신의 InputStream.

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

...

InputStream is = ....
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
byte[] buffer = new byte[8192];
int count = 0;
try {
  while ((count = is.read(buffer)) != -1) {
    baos.write(buffer, 0, count);
  }
}
finally {
  try {
    is.close();
  }
  catch (Exception ignore) {
  }
}

String charset = "UTF-8";
String inputStreamAsString = baos.toString(charset);

1
달성하려는 것에 대해 설명하십시오.
Ragunath Jawahar

14

Kotlin 사용자는 단순히 다음을 수행합니다.

println(InputStreamReader(is).readText())

이므로

readText()

Kotlin 표준 라이브러리의 기본 제공 확장 방법입니다.


스트림을 닫지 않기 때문에 실제로는 정확하지 않습니다. 추천 is.bufferedReader().use { it.readText() }합니다.
Max

9

JDK에서 가장 쉬운 방법은 다음 코드 스 니틀을 사용하는 것입니다.

String convertToString(InputStream in){
    String resource = new Scanner(in).useDelimiter("\\Z").next();
    return resource;
}

7

다음 은 새로운 Stream API 를 사용하여 다음에서 모든 행을 수집 하는 Java 8 기반 솔루션입니다 .InputStream

public static String toString(InputStream inputStream) {
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(inputStream));
    return reader.lines().collect(Collectors.joining(
        System.getProperty("line.separator")));
}

1
이전에 게시 된 모든 답변을 실제로 읽지 않은 것 같습니다. 스트림 API 버전은 이미 두 번 이상 존재 했습니다 .
Tagir Valeev

모든 솔루션을 살펴 봤지만 적합하지 않습니다. 간단한 설명이있는 두 줄이 정확하게 표시됩니다. 다른 솔루션의 try-catch-block은 예를 들어 사용되지 않습니다. 하지만 네 말이 맞아 너무 많은 답변으로 나는 빠른
도약

1
원본 파일을 읽지 않고 파일의 줄 끝을 OS의 줄 끝으로 변환하여 파일 내용을 변경할 수 있습니다.
Christian Hujer

7

측면에서 reduce, 그리고 concat그것이 자바 8과 같이 표현 될 수있다 :

String fromFile = new BufferedReader(new   
InputStreamReader(inputStream)).lines().reduce(String::concat).get();

1
엄청나게 느릴 것입니다.
Tagir Valeev 2016

왜 흥미 롭습니까? 좀 더 자세히 설명해 주시겠습니까?
libnull-dev 2016

1
StringBuilder를 사용하는 대신 루프에서 문자열을 연결하는 것이 나쁜 생각 인 이유를 모르십니까?
Tagir Valeev

네 말이 맞아 StringBuilder더 효율적일 수 있습니다. 확인하지만 내 요점은 불변으로 더 기능적인 접근 방식을 보여 주어야했습니다 String.
libnull-dev

기능적 접근 방식은 멋지지만 일반적으로 매우 비효율적입니다.
Lluis Martinez

4

스트림을 닫고 여전히 IOException을 발생시키는 JDK 7/8 응답 :

StringBuilder build = new StringBuilder();
byte[] buf = new byte[1024];
int length;
try (InputStream is = getInputStream()) {
  while ((length = is.read(buf)) != -1) {
    build.append(new String(buf, 0, length));
  }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.