java.lang.Stringからjava.io.InputStreamを取得するにはどうすればよいですか?


95

私が持っているString私として使いたいということをInputStream。Java 1.0ではを使用できますがjava.io.StringBufferInputStream、これは@Deprecrated(正当な理由により、文字セットエンコーディングを指定できない)です。

このクラスは文字をバイトに適切に変換しません。JDK 1.1以降、文字列からストリームを作成するための推奨される方法は、StringReader クラスを使用する方法です。

あなたは、作成することができjava.io.Readerjava.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 2013

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

3
確かに、システム内のどこかで文字列が具体化されることに反対する「文字列をメモリに具体化」したくないので、opは使用しない回避策です。–
Fotis Paraskevopoulos

カスタムオブジェクトを入力ストリームのソースに変換するライブラリはありますか。IOUtils.toInputStream(MyObject object)のようなもの?
nawazish-stackoverflow 2017

5

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


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


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

まあ、1つの可能な方法は次のとおりです。

  • を作成する PipedOutputStream
  • パイプで PipedInputStream
  • OutputStreamWriter周りをラップしPipedOutputStreamます(コンストラクターでエンコードを指定できます)
  • Etvoilá、あなたが書いたものは何OutputStreamWriterからでも読むことができますPipedInputStream

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


1
興味深い...もちろん、この解決策では、文字列全体をメモリ内に具体化するか、読み取りスレッドで飢餓に陥るかのいずれかになると思います。どこかに実際の実装があることをまだ望んでいます。
Jared Oberhaus、

5
Piped(Input | Output)Streamには注意する必要があります。ドキュメントに従って:「...スレッドをデッドロックする可能性があるため、単一のスレッドから両方のオブジェクトを使用することはお勧めしません...」 java.sun.com/j2se/1.4.2/docs/api/java/ io / PipedInputStream.html
ブライアンカイル

1

解決策は、独自にロールして、必要に応じてsのチャンクまたはチャンクをバイトの配列にエンコードInputStreamするために使用java.nio.charset.CharsetEncoderする可能性が高い実装を作成することです。charcharInputStream


1
一度に1文字ずつ物事を行うと、コストがかかります。そのため、一度にバッファを読み取ることができるInputStreamのような「チャンクイテレータ」を用意しています。
トム・ホーティン-09年

私はトムに同意する-あなたは本当に一度、この1つの文字を行うにはしたくありません。
エディ

1
データが本当に小さい場合、および他のもの(ネットワーク遅延など)に時間がかかる場合を除きます。その後、それは問題ではありません。:)
アンドレス・リオフリオ

0

org.hsqldb.libライブラリを利用できます。

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

1
一般に、コードの目的を説明する質問が含まれていると、質問がはるかに役立ちます。
ピーター

-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.