from - ¿Cómo puedo obtener un java.io.InputStream de un java.lang.String?
inputstreamreader to inputstream java (8)
Tengo un String que quiero usar como InputStream . En Java 1.0, puede usar java.io.StringBufferInputStream , pero eso ha sido @Deprecrated (por una buena razón: no puede especificar la codificación del juego de caracteres):
Esta clase no convierte correctamente los caracteres en bytes. A partir de JDK 1.1, la forma preferida de crear una secuencia a partir de una cadena es a través de la clase
StringReader.
Puede crear un java.io.Reader con java.io.StringReader , pero no hay adaptadores para tomar un Reader y crear un InputStream .
Encontré un error antiguo que pedía un reemplazo adecuado, pero no existe tal cosa, por lo que puedo decir.
La solución sugerida frecuentemente es usar java.lang.String.getBytes() como entrada para java.io.ByteArrayInputStream :
public InputStream createInputStream(String s, String charset)
throws java.io.UnsupportedEncodingException {
return new ByteArrayInputStream(s.getBytes(charset));
}
pero eso significa materializar toda la String en la memoria como una matriz de bytes, y anula el propósito de una secuencia. En la mayoría de los casos, esto no es gran cosa, pero estaba buscando algo que preservara la intención de una transmisión: que la menor cantidad posible de datos se (re) materialice en la memoria.
Bueno, una forma posible es:
- Crea un
PipedOutputStream -
PipedInputStreama unPipedInputStream -
PipedOutputStreamunOutputStreamWriteralrededor dePipedOutputStream(puede especificar la codificación en el constructor) - ¡Et voilá, todo lo que escribes en
OutputStreamWriterse puede leer desdePipedInputStream!
Por supuesto, esto parece una forma bastante hackosa de hacerlo, pero al menos es una manera.
En mi opinión, la manera más fácil de hacerlo es presionando los datos a través de un escritor:
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 implementación de JVM que estoy utilizando empujó los datos a través de fragmentos de 8K, pero podría tener algún efecto en el tamaño del búfer reduciendo el número de caracteres escritos a la vez y llamando al color.
Una alternativa a escribir su propio envoltorio CharsetEncoder para usar un Escritor para codificar los datos, aunque es algo doloroso hacer lo correcto. Esta debería ser una implementación confiable (si ineficiente):
/** 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);
}
}
}
Hay un adaptador de Apache Commons-IO que se adapta de Reader a InputStream, que se llama ReaderInputStream .
Código de ejemplo:
@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));
}
Referencia: https://.com/a/27909221/5658642
Puede tomar la ayuda de la biblioteca org.hsqldb.lib.
public StringInputStream(String paramString)
{
this.str = paramString;
this.available = (paramString.length() * 2);
}
Sé que esta es una vieja pregunta, pero tuve el mismo problema hoy, y esta fue mi solución:
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++);
}
};
}
Si no le importa una dependencia en el paquete commons-io , puede usar el método IOUtils.toInputStream (String text) .
Una solución es java.nio.charset.CharsetEncoder suya, creando una implementación de InputStream que probablemente usaría java.nio.charset.CharsetEncoder para codificar cada char o fragmento de char a una matriz de bytes para el InputStream según sea necesario.
Actualización: esta respuesta es precisamente lo que el OP no quiere. Por favor, lea las otras respuestas.
Para aquellos casos en los que no nos importa que los datos se vuelvan a materializar en la memoria, use:
new ByteArrayInputStream(str.getBytes("UTF-8"))