java.lang.String에서 java.io.InputStream을 어떻게 얻을 수 있습니까?


95

나는이 String내가으로 사용하도록을 InputStream. Java 1.0에서는를 사용할 수 java.io.StringBufferInputStream있지만 그랬습니다 @Deprecrated(좋은 이유가 있습니다. 문자 집합 인코딩을 지정할 수 없음).

이 클래스는 문자를 바이트로 올바르게 변환하지 않습니다. JDK 1.1부터 문자열에서 스트림을 만드는 데 선호되는 방법은 StringReader 클래스를 사용하는 것입니다.

당신은 만들 수 java.io.Reader와를 java.io.StringReader하지만을 할 어댑터가없는 Reader과를 만들 수는 InputStream.

적절한 교체를 요구 하는 오래된 버그를 찾았 지만, 내가 말할 수있는 한 그런 것은 존재하지 않습니다.

자주 제안되는 해결 방법은 다음에 대한 java.lang.String.getBytes()입력으로 사용 하는 것입니다 java.io.ByteArrayInputStream.

public InputStream createInputStream(String s, String charset)
    throws java.io.UnsupportedEncodingException {

    return new ByteArrayInputStream(s.getBytes(charset));
}

그러나 그것은 String메모리 의 전체 를 바이트 배열로 구체화하는 것을 의미 하며 스트림의 목적을 무효화합니다. 대부분의 경우 이것은 큰 문제는 아니지만 스트림의 의도를 보존 할 수있는 무언가를 찾고있었습니다. 가능한 한 적은 양의 데이터가 메모리에 (재) 구체화되는 것입니다.

답변:


78

업데이트 : 이 답변은 OP가 원하지 않는 것입니다. 다른 답변을 읽으십시오.

메모리에서 다시 구체화되는 데이터에 대해 신경 쓰지 않는 경우 다음을 사용하십시오.

new ByteArrayInputStream(str.getBytes("UTF-8"))

3
이 답변에 의해 제안 된 해결책은 질문에 의해 예상되고, 고려되고, 거부되었습니다. 그래서 제 생각에는이 답변을 삭제해야합니다.
— Mike Nakis 2013

1
당신이 옳을 수도 있습니다. 나는 원래 OP의 질문에 대한 실제 답변이 아니기 때문에 아마도 의견을 남겼습니다.
— Andres Riofrio

28
질문 제목 때문에 여기에 오는 방문자로서이 답변이 여기에있어 기쁩니다. 따라서 :이 답변을 삭제하지 마십시오. "이 답변은 OP가 원하지 않는 답변입니다. 다른 답변을 읽어보세요." 충분하다.
— Yaakov Belch 2013

10
java7 기준 :new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8))
— 느린

19

commons-io 패키지 에 대한 종속성이 마음에 들지 않으면 IOUtils.toInputStream (String text) 메서드를 사용할 수 있습니다 .


11
이 경우`return new ByteArrayInputStream (input.getBytes ()); '외에는 아무것도하지 않는 종속성을 추가합니다. 정말 의존할만한 가치가 있습니까? 솔직히 말해서, 그렇지 않습니다.
— whaefelinger 2012

3
사실, 시스템의 다른 어딘가에서 구체화되는 문자열에 대해 "문자열을 메모리로 구체화"하고 싶지 않기 때문에 op가 사용하지 않으려는 해결 방법 외에는 정확히 다음과 같습니다.)
— Fotis Paraskevopoulos

사용자 정의 개체를 입력 스트림의 소스로 변환하는 라이브러리가 있습니까? IOUtils.toInputStream (MyObject object)과 같은 것입니까?
— nawazish-stackoverflow

5

Reader에서 InputStream으로 조정되는 Apache Commons-IO의 어댑터가 있습니다 . 이는 ReaderInputStream 이라는 이름 입니다 .

예제 코드 :

@Test
public void testReaderInputStream() throws IOException {
    InputStream inputStream = new ReaderInputStream(new StringReader("largeString"), StandardCharsets.UTF_8);
    Assert.assertEquals("largeString", IOUtils.toString(inputStream, StandardCharsets.UTF_8));
}

참조 : https://stackoverflow.com/a/27909221/5658642


3

내 생각에 가장 쉬운 방법은 Writer를 통해 데이터를 푸시하는 것입니다.

public class StringEmitter {
  public static void main(String[] args) throws IOException {
    class DataHandler extends OutputStream {
      @Override
      public void write(final int b) throws IOException {
        write(new byte[] { (byte) b });
      }
      @Override
      public void write(byte[] b) throws IOException {
        write(b, 0, b.length);
      }
      @Override
      public void write(byte[] b, int off, int len)
          throws IOException {
        System.out.println("bytecount=" + len);
      }
    }

    StringBuilder sample = new StringBuilder();
    while (sample.length() < 100 * 1000) {
      sample.append("sample");
    }

    Writer writer = new OutputStreamWriter(
        new DataHandler(), "UTF-16");
    writer.write(sample.toString());
    writer.close();
  }
}

JVM 구현은 8K 청크로 푸시 된 데이터를 사용하고 있지만 한 번에 쓰는 문자 수를 줄이고 flush를 호출하여 버퍼 크기에 영향을 줄 수 있습니다.


Writer를 사용하여 데이터를 인코딩하는 자체 CharsetEncoder 래퍼를 작성하는 대신 올바른 작업을 수행하는 것은 다소 고통 스럽습니다. 이것은 신뢰할 수있는 (비효율적 인 경우) 구현이어야합니다.

/** Inefficient string stream implementation */
public class StringInputStream extends InputStream {

  /* # of characters to buffer - must be >=2 to handle surrogate pairs */
  private static final int CHAR_CAP = 8;

  private final Queue<Byte> buffer = new LinkedList<Byte>();
  private final Writer encoder;
  private final String data;
  private int index;

  public StringInputStream(String sequence, Charset charset) {
    data = sequence;
    encoder = new OutputStreamWriter(
        new OutputStreamBuffer(), charset);
  }

  private int buffer() throws IOException {
    if (index >= data.length()) {
      return -1;
    }
    int rlen = index + CHAR_CAP;
    if (rlen > data.length()) {
      rlen = data.length();
    }
    for (; index < rlen; index++) {
      char ch = data.charAt(index);
      encoder.append(ch);
      // ensure data enters buffer
      encoder.flush();
    }
    if (index >= data.length()) {
      encoder.close();
    }
    return buffer.size();
  }

  @Override
  public int read() throws IOException {
    if (buffer.size() == 0) {
      int r = buffer();
      if (r == -1) {
        return -1;
      }
    }
    return 0xFF & buffer.remove();
  }

  private class OutputStreamBuffer extends OutputStream {

    @Override
    public void write(int i) throws IOException {
      byte b = (byte) i;
      buffer.add(b);
    }

  }

}

2

가능한 한 가지 방법은 다음과 같습니다.

  • 만들기 PipedOutputStream
  • 파이프를 PipedInputStream
  • OutputStreamWriter주위를 감싸 십시오 PipedOutputStream(생성자에서 인코딩을 지정할 수 있습니다)
  • Et voilá,에 작성하는 모든 OutputStreamWriter내용은 PipedInputStream!

물론 이것은 그것을하기위한 다소 험난한 방법처럼 보이지만 적어도 그것은 방법입니다.


1
흥미롭게도 ... 물론이 솔루션을 사용하면 전체 문자열을 메모리에 구체화하거나 읽기 스레드에서 굶주리게 될 것이라고 믿습니다. 어딘가에 실제 구현이 있기를 여전히 바라고 있습니다.
— Jared Oberhaus

5
Piped (Input | Output) Stream에주의해야합니다. 문서에 따르면 : "... 스레드를 교착 상태로 만들 수 있으므로 단일 스레드에서 두 개체를 모두 사용하려는 시도는 권장되지 않습니다 ..." java.sun.com/j2se/1.4.2/docs/api/java/ io / PipedInputStream.html
— Bryan Kyle

1

해결책은 필요에 따라 각각 또는 청크 를 바이트 배열 로 인코딩하는 데 InputStream사용할 구현을 만드는 것입니다 .java.nio.charset.CharsetEncodercharcharInputStream


1
한 번에 한 캐릭터 씩하는 것은 비용이 많이 듭니다. 이것이 우리가 한 번에 버퍼를 읽을 수 있도록하는 InputStream과 같은 "청크 반복기"를 갖는 이유입니다.
— Tom Hawtin-tackline

톰 동의 - 당신은 정말 한 번에이 하나 개의 문자를 싶지 않아.
— Eddie

1
데이터가 정말 작고 다른 것 (예 : 네트워크 대기 시간)이 더 오래 걸리는 경우가 아니면. 그럼 상관 없어요. :)
— Andres Riofrio

0

org.hsqldb.lib 라이브러리의 도움을받을 수 있습니다.

public StringInputStream(String paramString)
  {
    this.str = paramString;
    this.available = (paramString.length() * 2);
  }

1
일반적으로 질문은 코드의 목적에 대한 설명이 포함 된 경우 훨씬 더 유용합니다.
— Peter

-1

나는 이것이 오래된 질문이라는 것을 알고 있지만 오늘 나도 같은 문제가 있었고 이것이 내 해결책이었습니다.

public static InputStream getStream(final CharSequence charSequence) {
 return new InputStream() {
  int index = 0;
  int length = charSequence.length();
  @Override public int read() throws IOException {
   return index>=length ? -1 : charSequence.charAt(index++);
  }
 };
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.