在Java中将大于2GB的文件读入内存

8

由于ByteArrayInputStream限制为2GB,是否有可替代的解决方案,可以将2.3GB(甚至更大)文件的整个内容存储到InputStream中以供Stax2读取?

当前代码:

            XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
            XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(in); //ByteArrayInputStream????
            try
            {
                SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

                Schema schema = factory.newSchema(new StreamSource(schemaInputStream));
                Validator validator = schema.newValidator();
                validator.validate(new StAXSource(xmlStreamReader));

            }

            finally
            {
                xmlStreamReader.close();
            }

在性能调优中,变量in不能来自磁盘。我有大量的内存。


在.NET中,同样存在这个问题,并有几种解决方案。请查看此链接 - ikh
也许可以将其分成几个包含文件吗? - Joop Eggen
4个回答

5
整个StAX2的重点在于您无需将文件读入内存中。您只需提供源,让StAX StreamReader根据需要提取数据即可。
您是否有其他未在问题中展示的附加限制?
如果您拥有大量内存并且想获得良好的性能,请使用大型字节缓冲区包装InputStream,让缓冲区为您进行缓冲处理。
// 4 meg buffer on the stream
InputStream buffered = new BufferedInputStream(schemaInputStream, 1024 * 1024 * 4);

在Java中解决这个问题的另一种方法是创建一个RAMDisk并将文件存储在其中,这样就可以将问题从Java中移除,因为您的基本限制是单个数组中只能拥有略小于 Integer.MAX_VALUE 个值。

2
这是一个性能测试,我需要找到瓶颈。我的上级明确地要求我进行这个测试:将整个文件加载到内存中,验证它并向我的上司提供时间数据。 - usr-local-ΕΨΗΕΛΩΝ
1
是的,我正要建议使用RAM磁盘。这样算吗?所有数据都在内存中,但并非全部在JVM的内存中。 - chiastic-security
我会考虑使用ramdisk,+1 @chiastic-security - usr-local-ΕΨΗΕΛΩΝ
我已经多次尝试过,但归根结底,如果你追求原始性能,最好使用内存映射的ByteBuffer,而这与StAX API不兼容,你仍然需要进行内存复制。此时,你的限制因素将是数据解析,而不是源的性能。我猜想一个具有足够大缓冲区的BufferedInputStream将会满足你的需求。 - rolfl
@rolfl 我完全同意,但我正在尝试找到一种方法来让 OP 的老板满意 :) 这似乎是在启动之前将整个内容放入 JVM 内存中的最佳方式。 - chiastic-security
显示剩余3条评论

3
使用NIO将文件读入一个巨大的ByteBuffer中,然后创建一个流类来读取这个ByteBuffer。在开源项目中有几个这样的类可供使用。

0

如果你有大量的内存,那么你不会得到任何性能提升。无论哪种方式,它只会被读取一次,并且磁盘缓存将确保它以最佳方式完成。只需使用基于磁盘的输入流即可。


-1

你可以使用内存将数据压缩到一个位置。

ByteArrayOutputStream baos = new ByteArrayOutputStream
... new GZIPOutputStream(baos));

byte[] bytes = baos.toByteArray(); // < 100 MB?

ByteArrayInputStream ....

然后稍后将输入流包装在GZIPInputStream中。

仍然有轻微的减速,但对于XML来说应该是理想的。


解决内存占用问题的好方法。特别是对于XML,一个2.3GB的文件可以压缩到70MB。我应该接受这个答案,因为它是根据问题范围给出的完美答案。然而,这个问题没有很好地表达(X-Y问题):我需要进行XML验证基准测试,压缩开销不是最好的选择。因此,你的解决方案并不能成为通用解决方案,因为有些数据可能非常庞大,超过2GB时进行压缩,但这可能会导致不同的问答世界。 - usr-local-ΕΨΗΕΛΩΝ
好的,感谢您仍在尝试(2.3 GB -> 70 MB)。我将为其他有类似问题的人留下答案,因为gzip经常被忽视。就像使用RAM磁盘/固态硬盘一样。 - Joop Eggen
实际上,我的业务案例(ECB ABS报告)需要对磁盘上生成的XML进行GZIP压缩,所以我不必尝试您的代码,我已经得到了答案;-) - usr-local-ΕΨΗΕΛΩΝ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接