任何实用程序 class/method 获取大字符串和 return InputStream?

Any util class/method to take a large String and return an InputStream?

我正在寻找一些实用程序 class/method 来处理大 String 和 return 和 InputStream.

如果String很小,我可以这样做:

InputStream is = new ByteArrayInputStream(str.getBytes(<charset>));

但是当String很大(1MB、10MB或更多)时,当场分配一个字节数组是我的字符串的1到2倍(或更多?)。 (并且由于在完成所有编码之前您不知道要分配多少字节,所以我认为在分配最终字节数组之前必须分配其他 arrays/buffers)。

我有性能需求,想优化这个操作

我认为理想情况下,我正在寻找的 class/method 会在消耗 InputStream 时一次一小块地动态编码字符,因此内存分配不会大幅增加。

看了apache commons的源码IOUtils.toInputStream(..),发现它也是把String一次性转成一个大字节数组

并且 StringBufferInputStream 已弃用,并且不能正确完成工作。

哪里有这样的工具class/method?或者我可以只写几行代码来做到这一点?

这个功能的需要是,在其他地方,我使用了一个 util 方法,它接受一个 InputStream 并从这个 InputStream.

流出字节

我好像没有其他人在寻找这样的东西。我是不是哪里弄错了什么?

我已经开始为此编写自定义 class,但如果有 better/proper/right solution/correction 满足我的需要,我会停止。

对我来说有一个根本性的问题。一开始为什么你的内存中有这么大的 Strings...

总之,你可以试试这个:

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

如果您将大字符串作为参数传递,则内存已分配。一个这么大的字符串甚至不能被压入堆栈(大多数时候最大堆栈大小为 1MB)所以它被分配到堆上只是为了将它作为参数传递。我能看到避免这种情况的唯一方法是在磁盘上创建一棵树,在树上行走时一次流回一个字符。如果您有多个大字符串,也许可以在 Trie 或 DAWG 中为它们编制索引并遍历该结构。这将消除字符串之间的许多重复字符。但是,我需要更多地了解字符串代表什么才能提供进一步帮助。

Java 内置库假定您只需要在输出中从字符转换为字节,而不是输入。 Apache Commons IO 库有 ReaderInputStream,但是,它可以包装一个 StringReader 来得到你想要的。

实现您自己的字符串支持输入流:

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 方法添加到此实现中。