96

I have a String that I want to use as an InputStream. In Java 1.0, you could use java.io.StringBufferInputStream, but that has been @Deprecrated (with good reason--you cannot specify the character set encoding):

This class does not properly convert characters into bytes. As of JDK 1.1, the preferred way to create a stream from a string is via the StringReader class.

You can create a java.io.Reader with java.io.StringReader, but there are no adapters to take a Reader and create an InputStream.

I found an ancient bug asking for a suitable replacement, but no such thing exists--as far as I can tell.

The oft-suggested workaround is to use java.lang.String.getBytes() as input to java.io.ByteArrayInputStream:

public InputStream createInputStream(String s, String charset)
 throws java.io.UnsupportedEncodingException {
 return new ByteArrayInputStream(s.getBytes(charset));
}

but that means materializing the entire String in memory as an array of bytes, and defeats the purpose of a stream. In most cases this is not a big deal, but I was looking for something that would preserve the intent of a stream--that as little of the data as possible is (re)materialized in memory.

asked May 8, 2009 at 0:30
0

9 Answers 9

78

Update: This answer is precisely what the OP doesn't want. Please read the other answers.

For those cases when we don't care about the data being re-materialized in memory, please use:

new ByteArrayInputStream(str.getBytes("UTF-8"))
Yaakov Belch
4,8931 gold badge36 silver badges40 bronze badges
answered Jan 2, 2013 at 23:19
4
  • 3
    The solution proposed by this answer has been anticipated, contemplated upon, and rejected by the question. So in my opinion, this answer should be deleted. Commented Jul 14, 2013 at 12:09
  • 1
    You might be right. I originally made it a comment probably because it wasn't an actual answer to OP's question. Commented Jul 15, 2013 at 18:52
  • 28
    As a visitor coming here because of the question title, I am happy that this answer is here. So: Please don't delete this answer. The remark at the top "This answer is precisely what the OP doesn't want. Please read the other answers." is sufficient. Commented Jul 29, 2013 at 14:01
  • 10
    As of java7: new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8)) Commented Jan 17, 2014 at 22:25
19

If you don't mind a dependency on the commons-io package, then you could use the IOUtils.toInputStream(String text) method.

Stephan
43.2k69 gold badges245 silver badges342 bronze badges
answered Nov 7, 2011 at 20:48
3
  • 12
    In that case you add a dependency which does nothing else than `return new ByteArrayInputStream(input.getBytes());' Is that really worth a dependency? In all honesty, no - it isn't. Commented Feb 14, 2012 at 12:53
  • 3
    True, besides it is exactly the workaround the op doesn't wan't to use because the he does not want to "materialize the string into memory" oposed to the string being materialized somewhere else in the system :) Commented Jun 23, 2012 at 15:47
  • Do we have any library which converts custom object into source of input stream; something like IOUtils.toInputStream(MyObject object)? Commented Jan 28, 2017 at 16:05
6

There is an adapter from Apache Commons-IO which adapts from Reader to InputStream, which is named ReaderInputStream.

Example code:

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

Reference: https://stackoverflow.com/a/27909221/5658642

answered Sep 6, 2016 at 9:45
0
3

To my mind, the easiest way to do this is by pushing the data through a 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();
 }
}

The JVM implementation I'm using pushed data through in 8K chunks, but you could have some affect on the buffer size by reducing the number of characters written at one time and calling flush.


An alternative to writing your own CharsetEncoder wrapper to use a Writer to encode the data, though it is something of a pain to do right. This should be a reliable (if inefficient) implementation:

/** 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);
 }
 }
}
answered May 8, 2009 at 14:31
0
2

Well, one possible way is to:

  • Create a PipedOutputStream
  • Pipe it to a PipedInputStream
  • Wrap an OutputStreamWriter around the PipedOutputStream (you can specify the encoding in the constructor)
  • Et voilá, anything you write to the OutputStreamWriter can be read from the PipedInputStream!

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

answered May 8, 2009 at 0:40
2
  • 1
    Interesting... of course, with this solution I believe that you would either materialize the whole string in memory, or suffer starvation on the reading thread. Still hoping that there's a real implementation somewhere. Commented May 8, 2009 at 0:50
  • 5
    You have to be careful with Piped(Input|Output)Stream. As per the docs: "...Attempting to use both objects from a single thread is not recommended, as it may deadlock the thread..." java.sun.com/j2se/1.4.2/docs/api/java/io/PipedInputStream.html Commented May 8, 2009 at 5:03
1

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.

answered May 8, 2009 at 0:52
3
  • 1
    Doing things one character at a time is expensive. That's why we have "chunked iterators" like InputStream that allow us to read a buffer at a time. Commented May 8, 2009 at 0:55
  • I agree with Tom -- you really don't want to do this one character at a time. Commented May 8, 2009 at 1:11
  • 1
    Unless the data is really small, and other things (network latency, for example) take longer. Then it doesn't matter. :) Commented May 22, 2012 at 4:20
0

I am not aware of any possibility with pure JDK means. The StringBufferInputStream is deprecated because it does not convert characters into bytes properly.
If Guava library is available in the project, the internal ReaderInputStream can be used via:

public InputStream asInputStream(CharSequence chars, Charset charset) throws IOException {
 return CharSource.wrap(chars).asByteSource(charset).openStream();
}

Under the hood the CharSequence/String is wrapped into a Reader which in turn is wrapped into the InputStream mentioned in the beginning. This allows the conversion via streaming.

answered Jan 24, 2024 at 12:40
-1

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

public StringInputStream(String paramString)
 {
 this.str = paramString;
 this.available = (paramString.length() * 2);
 }
answered Jun 28, 2017 at 11:07
1
  • 1
    Generally, questions are much more useful if they include an explanation of what the code is intended to do. Commented Jun 28, 2017 at 11:28
-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++);
 }
 };
}
answered Aug 22, 2013 at 13:38
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.