Ответ 1
Обновление: Этот ответ - именно то, что OP не хочет. Пожалуйста, прочитайте другие ответы.
В тех случаях, когда нам не нужны данные, которые перепрофилируются в памяти, используйте:
new ByteArrayInputStream(str.getBytes("UTF-8"))
У меня есть String
, который я хочу использовать как InputStream
. В Java 1.0 вы можете использовать java.io.StringBufferInputStream
, но это было @Deprecrated
(с полным основанием - вы не можете указать кодировку набора символов ):
Этот класс неправильно конвертирует символов в байты. Начиная с JDK 1.1, предпочтительный способ создания потока из строки через
StringReader
класс.
Вы можете создать java.io.Reader
с java.io.StringReader
, но нет адаптеров для принятия Reader
и создания 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
в памяти в виде массива байтов и побеждает цель потока. В большинстве случаев это не имеет большого значения, но я искал что-то, что бы сохранить намерение потока - что как можно меньше данных (re) материализовалось в памяти.
Обновление: Этот ответ - именно то, что OP не хочет. Пожалуйста, прочитайте другие ответы.
В тех случаях, когда нам не нужны данные, которые перепрофилируются в памяти, используйте:
new ByteArrayInputStream(str.getBytes("UTF-8"))
Если вы не против зависимости от пакета commons-io, вы можете использовать метод IOUtils.toInputStream(String text).
На мой взгляд, самый простой способ сделать это - нажать данные через 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. Я использую push-данные через 8K-фрагменты, но вы можете повлиять на размер буфера, уменьшив количество символов, написанных за один раз, и вызвав флеш.
Альтернатива написанию собственной оболочки 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);
}
}
}
Существует адаптер от 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));
}
Ссылка: fooobar.com/questions/42140/...
Ну, один из возможных способов:
PipedOutputStream
PipedInputStream
OutputStreamWriter
вокруг PipedOutputStream
(вы можете указать кодировку в конструкторе)OutputStreamWriter
, можно прочитать из PipedInputStream
!Конечно, это похоже на довольно хакерский способ сделать это, но, по крайней мере, это способ.
Решение состоит в том, чтобы свернуть свой собственный, создав реализацию InputStream
, которая, вероятно, будет использовать java.nio.charset.CharsetEncoder
для кодирования каждого char
или фрагмента char
для массива байтов для InputStream
по мере необходимости.
Я знаю, что это старый вопрос, но сегодня у меня была та же проблема, и это было моим решением:
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++);
}
};
}
Вы можете воспользоваться библиотекой org.hsqldb.lib.
public StringInputStream(String paramString)
{
this.str = paramString;
this.available = (paramString.length() * 2);
}