任何 util 类/方法来获取大字符串并返回 InputStream?
Posted
技术标签:
【中文标题】任何 util 类/方法来获取大字符串并返回 InputStream?【英文标题】:Any util class/method to take a large String and return an InputStream? 【发布时间】:2015-03-10 14:53:57 【问题描述】:我正在寻找一些实用类/方法来获取一个大的String
并返回一个InputStream
。
如果String
很小,我可以这样做:
InputStream is = new ByteArrayInputStream(str.getBytes(<charset>));
但是当String
很大(1MB、10MB 或更多)时,会当场分配一个 1 到 2 倍(或更多?)与我的 String 一样大的字节数组。 (而且由于在所有编码完成之前您不知道要分配多少字节,我认为在分配最终字节数组之前必须分配其他数组/缓冲区)。
我有性能要求,想优化这个操作。
我认为,理想情况下,我正在寻找的类/方法会在 InputStream 被消耗时一次对一个小块的字符进行动态编码,因此不会大幅增加内存分配。
看了一下apache commonsIOUtils.toInputStream(..)
的源码,看到它也一口气把String转成大字节数组了。
而StringBufferInputStream
已被弃用,并且无法正常工作。
在任何地方都有这样的 util 类/方法吗?或者我可以写几行代码来做到这一点?
对此的功能需求是,在其他地方,我正在使用一个 util 方法,该方法采用 InputStream
并从该 InputStream
流出字节。
我似乎没有其他人在寻找这样的东西。我是不是在某个地方弄错了什么?
我已经开始为此编写一个自定义类,但如果有更好/正确/正确的解决方案/更正我的需要,我会停止。
【问题讨论】:
等等...您知道String
是一个内部char
s 的数组,而char
是两个byte
s 长吗?更重要的是,你甚至不考虑编码......
在StringReader 之上使用ReaderInputStream 怎么样?另请参阅***.com/questions/837703/…。
对,我希望能找到一些东西,让我指定我想要的编码/字符集。
@shmosel,我会把它作为答案。
@LouisWasserman 现在没有时间研究它。随意使用它。
【参考方案1】:
Java 内置库假定您只需要在输出中从字符转换为字节,而不是输入。 Apache Commons IO 库有 ReaderInputStream,但是,它可以包装 StringReader
来获得你想要的。
【讨论】:
正是,正是我想要的【参考方案2】:实现您自己的基于字符串的输入流:
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 方法。
【讨论】:
【参考方案3】:如果您将大字符串作为参数传递,则内存已分配。一个很大的字符串甚至不能被推入堆栈(大多数情况下最大堆栈大小为 1MB),因此在堆上分配它只是为了将其作为参数传递。我能看到避免这种情况的唯一方法是在磁盘上创建一棵树,当你在树上行走时,你一次流回一个字符。如果您有多个大字符串,也许可以在 Trie 或 DAWG 中对它们进行索引并遍历该结构。这将消除字符串之间的许多重复字符。但是,我需要进一步了解这些字符串所代表的含义。
【讨论】:
字符串已分配。只是不想分配另一个大字节数组作为中间步骤。【参考方案4】:对我来说,有一个基本问题。为什么你的内存里有这么大的String
s...
不管怎样,你可以试试这个:
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());
【讨论】:
为什么会比string.getBytes(charset)
更好?
@LouisWasserman 因为它可以检测到格式错误的输入...String
的.getBytes()
不会。
这会复制输入字符串,就像 getBytes 一样。
@Petter 是的,但它会检测到错误!您可以使用您的解码器仅读取部分内容(我在this project 中已经这样做了,但用于反向操作),但无论如何,这里的根本问题是为什么内存中存在如此大的字符串。 .以上是关于任何 util 类/方法来获取大字符串并返回 InputStream?的主要内容,如果未能解决你的问题,请参考以下文章