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.