webentwicklung-frage-antwort-db.com.de

Wie kann ich Java.io.InputStream von einem Java.lang.String erhalten?

Ich habe eine String, die ich als InputStream verwenden möchte. In Java 1.0 können Sie Java.io.StringBufferInputStream verwenden, dies war jedoch @Deprecrated (aus gutem Grund - Sie können die Zeichensatzkodierung nicht angeben):

Diese Klasse konvertiert nicht korrekt Zeichen in Bytes. Stand JDK 1.1, Die bevorzugte Methode zum Erstellen eines Streams von einer Zeichenfolge erfolgt über StringReader Klasse.

Sie können ein Java.io.Reader mit Java.io.StringReader erstellen, aber es gibt keine Adapter, die ein Reader und ein InputStream erstellen.

Ich habe ein uralter Bug gefunden, das nach einem geeigneten Ersatz fragt, aber so etwas existiert nicht - soweit ich das beurteilen kann.

Die häufig empfohlene Problemumgehung besteht in der Verwendung von Java.lang.String.getBytes() als Eingabe für Java.io.ByteArrayInputStream :

public InputStream createInputStream(String s, String charset)
    throws Java.io.UnsupportedEncodingException {

    return new ByteArrayInputStream(s.getBytes(charset));
}

dies bedeutet jedoch, dass das gesamte String im Speicher als Byte-Array verwirklicht wird, und der Zweck eines Streams besiegt wird. In den meisten Fällen ist dies keine große Sache, aber ich suchte nach etwas, das die Absicht eines Streams aufrechterhalten würde - dass so wenig Daten wie möglich im Speicher (wieder) materialisiert werden.

91
Jared Oberhaus

Update: Diese Antwort ist genau das, was das OP nicht will. Bitte lesen Sie die anderen Antworten.

Für die Fälle, in denen es uns nicht darum geht, dass die Daten im Speicher erneut materialisiert werden, verwenden Sie bitte:

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

Wenn Sie nichts an einer Abhängigkeit vom Paket commons-io interessiert, können Sie die Methode IOUtils.toInputStream (String text) verwenden.

18

Es gibt einen Adapter von Apache Commons-IO, der sich von Reader an InputStream anpasst, der ReaderInputStream heißt.

Beispielcode:

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

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

3
beat

Meiner Meinung nach ist dies der einfachste Weg, die Daten durch einen Writer zu pushen:

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

Die JVM-Implementierung, die ich in 8-KByte-Paketen verwende, verwende Daten, aber Sie könnten die Puffergröße beeinflussen, indem Sie die Anzahl der gleichzeitig geschriebenen Zeichen und den Aufruf von Flush verringern.


Eine Alternative zum Schreiben Ihres eigenen CharsetEncoder-Wrappers, um einen Writer zum Verschlüsseln der Daten zu verwenden, obwohl es ziemlich schmerzhaft ist, dies richtig zu tun. Dies sollte eine zuverlässige (wenn ineffiziente) Implementierung sein:

/** 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

Nun, ein möglicher Weg ist:

  • Erstellen Sie eine PipedOutputStream
  • Pipe zu einem PipedInputStream
  • Umwickeln Sie ein OutputStreamWriter um das PipedOutputStream (Sie können die Kodierung im Konstruktor angeben)
  • Et voilá, alles, was Sie in die OutputStreamWriter schreiben, kann von der PipedInputStream gelesen werden!

Natürlich scheint dies eine ziemlich hackhafte Art zu sein, aber es ist zumindest ein Weg.

2
Michael Myers

Eine Lösung besteht darin, Ihre eigene Rolle zu erstellen, indem Sie eine InputStream-Implementierung erstellen, die wahrscheinlich Java.nio.charset.CharsetEncoder zum Kodieren der einzelnen char-Elemente oder der einzelnen char-Blöcke in ein Array von Bytes für die InputStream-Instanz verwendet.

2
Jared Oberhaus

Ich weiß, das ist eine alte Frage, aber ich hatte heute selbst das gleiche Problem, und dies war meine Lösung:

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

Sie können sich an die Bibliothek org.hsqldb.lib wenden.

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