96 votes

Comment puis-je obtenir un java.io.InputStream de java.lang.Chaîne?

J'ai un String que je veux utiliser comme un InputStream. En Java 1.0, vous pouvez utiliser java.io.StringBufferInputStream, mais qui a été @Deprecrated (avec une bonne raison, vous ne pouvez pas spécifier le codage du jeu de caractères):

Cette classe ne comprend pas convertir correctement les caractères en octets. Comme de JDK 1.1, la meilleure façon de créer un flux à partir d'une chaîne est par l'intermédiaire de l' StringReader classe.

Vous pouvez créer un java.io.Reader avec java.io.StringReader, mais il n'existe pas de cartes de prendre un Reader et de créer un InputStream.

J'ai trouvé un ancien bug demander un remplacement convenable, mais pas une telle chose existe-autant que je puis dire.

L'oft a suggéré une solution de contournement est d'utiliser java.lang.String.getBytes() comme entrée d' java.io.ByteArrayInputStream:

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

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

mais que signifie à se matérialiser l'ensemble de l' String dans la mémoire comme un tableau d'octets, et de défaites le but d'un cours d'eau. Dans la plupart des cas, ce n'est pas une grosse affaire, mais je cherchais quelque chose qui permettrait de préserver l'intention d'un cours d'eau--que peu de données que possible est (re)matérialisée dans la mémoire.

78voto

Andres Riofrio Points 1950

Mise à jour: Cette réponse est précisément ce que l'OP ne veut pas. Veuillez lire les autres réponses.

Pour ces cas, quand nous ne nous soucions pas les données en cours de re-matérialisé dans la mémoire, veuillez utiliser:

new ByteArrayInputStream(str.getBytes("UTF-8"))

19voto

Si vous n'avez pas l'esprit d'une dépendance à l' commons-io paquet, alors vous pouvez utiliser les IOUtils.toInputStream(String texte) de la méthode.

3voto

McDowell Points 62645

À mon avis, la meilleure façon de le faire est de pousser les données par le biais d'un Écrivain:

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

La JVM je suis poussé à l'aide de données par le biais de 8K morceaux, mais vous pourriez avoir un effet sur la taille de la mémoire tampon en réduisant le nombre de caractères écrits à une époque et d'appeler flush.


Une alternative à l'écriture de votre propre CharsetEncoder wrapper pour l'utilisation d'un Écrivain pour coder les données, mais c'est quelque chose de difficile à faire. Ce doit être un fiable (si inefficace) mise en œuvre:

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

  }

}

2voto

Michael Myers Points 82361

Eh bien, une façon est de:

  • Créer un PipedOutputStream
  • Pipe à un PipedInputStream
  • Enroulez un OutputStreamWriter autour de la PipedOutputStream (vous pouvez spécifier l'encodage dans le constructeur)
  • Et voilá, tout ce que vous écrivez à l' OutputStreamWriter peut être lu à partir de l' PipedInputStream!

Bien sûr, cela semble être un plus à du bidouillage façon de le faire, mais au moins c'est une façon.

1voto

Jared Oberhaus Points 8877

Une solution est de faire rouler votre propre, la création d'un InputStream mise en œuvre que probable serait d'utiliser java.nio.charset.CharsetEncoder pour coder chaque char ou partie de l' chars à un tableau d'octets pour l' InputStream que nécessaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X