Любой метод/метод, чтобы взять большую строку и вернуть InputStream?
Я ищу некоторый класс/метод util, чтобы взять большой String
и вернуть InputStream
.
Если String
мал, я могу просто сделать:
InputStream is = new ByteArrayInputStream(str.getBytes(<charset>));
Но когда размер String
большой (1 МБ, 10 МБ или более), массив байтов от 1 до 2 раз (или более?), такой же большой, как моя строка, выделяется на месте. (И поскольку вы не знаете, сколько байтов выделяется точно до того, как все кодирование будет выполнено, я думаю, что должны быть другие массивы/буферы, выделенные до выделения финального байтового массива).
У меня есть требования к производительности и вы хотите оптимизировать эту операцию.
В идеале, я думаю, класс/метод, который я ищу, будет кодировать символы "на лету" на одном небольшом блоке за раз, когда потребляется InputStream, и поэтому не происходит большой всплеск распределения памяти.
Глядя на исходный код apache commons IOUtils.toInputStream(..)
, я вижу, что он также преобразует String в большой массив байтов за один раз.
И StringBufferInputStream
устарел и не выполняет работу должным образом.
Есть ли такой класс/метод использования из любого места? Или я могу написать пару строк кода, чтобы сделать это?
Функциональная необходимость в этом заключается в том, что в другом месте я использую метод util, который принимает InputStream
и выдает байты из этого InputStream
.
Я не думаю, что другие люди ищут что-то подобное. Я что-то придумываю где-то?
Я начал писать пользовательский класс для этого, но остановился бы, если бы было лучшее/правильное/правильное решение/исправление для моей потребности.
Ответы
Ответ 1
Встроенные библиотеки Java предполагают, что вам нужно будет только перейти от символов к байтам на выходе, а не вводить. Однако библиотеки IO Apache Commons IO ReaderInputStream, которые могут обернуть StringReader
, чтобы получить то, что вы хотите.
Ответ 2
Для меня существует фундаментальная проблема. Почему у вас есть такой огромный String
в памяти, в первую очередь...
В любом случае вы можете попробовать следующее:
public static InputStream largeStringToBytes(final String tooLarge,
final Charset charset)
{
final CharsetEncoder encoder = charset.newEncoder()
.onUnmappableCharacter(CodingErrorAction.REPORT);
final ByteBuffer buf = charset.encode(CharBuffer.wrap(tooLarge));
return new ByteArrayInputStream(buf.array());
}
Ответ 3
Если вы передаете большую строку в качестве параметра, тогда память уже выделена. Строка, которая не может быть даже вложена в стек (в большинстве случаев максимальный размер стека равен 1 МБ), поэтому он получает выделение в куче только для передачи его в качестве параметра. Единственный способ избежать этого - создать дерево на диске, на котором вы побросали назад, когда вы шли по дереву. Если у вас есть несколько больших строк, возможно, они могут индексировать их в Trie или DAWG и ходить по этой структуре. Это устранит многие повторяющиеся символы между строками. Но, мне нужно будет узнать больше о том, что представляют строки для дальнейшего содействия.
Ответ 4
Реализовать собственный поток, поддерживаемый строкой:
class StringifiedInputStream extends InputStream {
private int idx=0;
private final String str;
private final int len;
StringifiedInputStream(String str) {
this.str = str;
this.len = str.length();
}
@Override
public int read() throws IOException {
if(idx>=len)
return -1;
return (byte) str.charAt(idx++);
}
}
Это медленно, но он передает байты без дублирования массива байтов. Добавьте метод 3-arg к этой реализации, если скорость является проблемой.