Programing

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

crosscheck 2020. 9. 2. 14:11
반응형

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


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


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

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

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

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


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


내 생각에 가장 쉬운 방법은 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);
    }

  }

}

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

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

Of course, this seems like a rather hackish way to do it, but at least it is a way.


A solution is to roll your own, creating an InputStream implementation that likely would use java.nio.charset.CharsetEncoder to encode each char or chunk of chars to an array of bytes for the InputStream as necessary.


You can take help of org.hsqldb.lib library.

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

I know this is an old question but I had the same problem myself today, and this was my solution:

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

참고URL : https://stackoverflow.com/questions/837703/how-can-i-get-a-java-io-inputstream-from-a-java-lang-string

반응형