96

我有一个String我想用作InputStream. 在 Java 1.0 中,您可以使用java.io.StringBufferInputStream,但这已经是@Deprecrated(有充分的理由——您不能指定字符集编码):

此类没有正确地将字符转换为字节。从 JDK 1.1 开始,从字符串创建流的首选方法是通过StringReader 类。

您可以创建一个java.io.Readerwith java.io.StringReader,但没有适配器可以使用 aReader和创建一个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内存中的整个实体化为一个字节数组,并且违背了流的目的。在大多数情况下,这没什么大不了的,但我一直在寻找能够保留流意图的东西——尽可能少的数据在内存中(重新)物化。

4

8 回答 8

78

更新:这个答案正是 OP 不想要的。请阅读其他答案。

对于那些我们不关心在内存中重新实现数据的情况,请使用:

new ByteArrayInputStream(str.getBytes("UTF-8"))
于 2013-01-02T23:19:58.617 回答
19

如果您不介意对commons-io包的依赖,那么您可以使用IOUtils.toInputStream(String text)方法。

于 2011-11-07T20:48:24.643 回答
6

有一个来自 Apache Commons-IO 的适配器,它从 Reader 适配到 InputStream,它被命名为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

于 2016-09-06T09:45:12.320 回答
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 来对缓冲区大小产生一些影响。


编写自己的 CharsetEncoder 包装器以使用 Writer 对数据进行编码的替代方法,尽管正确地做是一件痛苦的事情。这应该是一个可靠(如果效率低下)的实现:

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

  }

}
于 2009-05-08T14:31:07.830 回答
2

好吧,一种可能的方法是:

当然,这似乎是一种相当老套的方式,但至少它是一种方式。

于 2009-05-08T00:40:54.650 回答
1

一种解决方案是自己动手,创建一个InputStream可能用于将每个或 s 块java.nio.charset.CharsetEncoder编码为字节数组的实现。charcharInputStream

于 2009-05-08T00:52:51.300 回答
0

您可以借助 org.hsqldb.lib 库。

public StringInputStream(String paramString)
  {
    this.str = paramString;
    this.available = (paramString.length() * 2);
  }
于 2017-06-28T11:07:44.127 回答
-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++);
  }
 };
}
于 2013-08-22T13:38:13.783 回答