web-dev-qa-db-ja.com

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全体をバイトの配列として具体化することを意味し、ストリームの目的を無効にします。ほとんどの場合、これは大したことではありませんが、ストリームの意図を保存するものを探していました-可能な限り少ないデータがメモリに(再)実体化されます。

92
Jared Oberhaus

更新:この回答は、OPが望んでいないものです。他の答えを読んでください。

データがメモリに再実体化されることを気にしない場合は、次を使用してください:

new ByteArrayInputStream(str.getBytes("UTF-8"))
78
Andres Riofrio

commons-io パッケージへの依存関係を気にしない場合は、 IOUtils.toInputStream(String text) メソッドを使用できます。

18

Readerから ReaderInputStream という名前のInputStreamに適応するApache Commons-IOのアダプターがあります。

サンプルコード:

@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

4
beat

私の考えでは、これを行う最も簡単な方法は、ライターを介してデータをプッシュすることです。

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のチャンクで使用しますが、一度に書き込まれる文字数を減らしてフラッシュを呼び出すことで、バッファーサイズに影響を与える可能性があります。


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

  }

}
3
McDowell

さて、1つの可能な方法は:

  • PipedOutputStream を作成します
  • パイプで PipedInputStream
  • OutputStreamWriterPipedOutputStreamの周りにラップします(コンストラクターでエンコードを指定できます)
  • など、OutputStreamWriterに書き込むものはすべてPipedInputStreamから読み取ることができます!

もちろん、これはややハック的な方法のように見えますが、少なくとも方法です。

2
Michael Myers

解決策は、独自のロールを作成し、Java.nio.charset.CharsetEncoderを使用して各InputStreamまたはcharsのチャンクをバイト配列にエンコードするchar実装を作成することです。必要に応じてInputStream.

1
Jared Oberhaus

私はこれが古い質問であることを知っていますが、今日私は同じ問題を抱えていました。これが私の解決策でした:

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

Org.hsqldb.libライブラリの助けを借りることができます。

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