在试图追查
为什么?
我偶然发现:
import java.io._
import java.util.zip._
val bo = new ByteArrayOutputStream()
val zo = new ZipOutputStream(bo)
zo.putNextEntry(new ZipEntry("1"))
zo.write("hello".getBytes())
zo.write("\nhello".getBytes())
val bytes1 = bo.toByteArray()
// bytes1: Array[Byte] = Array(80, 75, 3, 4, 20, 0, 8, 8, 8, 0, 107, -121, -9, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 49)
bo.reset()
zo.write("hello".getBytes())
val bytes2 = bo.toByteArray() // bytes2: Array[Byte] = Array()
zo.flush()
val bytes2 = bo.toByteArray() // bytes2: Array[Byte] = Array()
bo.size //res11: Int = 0
zo.putNextEntry() // If I make a new entry it works but I can't do this in real code...
bo.size // res17: Int = 66
当我重置底层的字节输出流时,它似乎会导致zipOutputstream记录下任何内容。这让我很惊讶,所以我开始研究
underlying source code of ZipOutputStream
. 我注意到默认方法是deflated,它只调用
DeflaterOutputStream#write
然后,我研究了deflater代码本身,认为在压缩算法中可能有更深层的东西,我不理解它要求流不被重置,或者受到它的某种影响。我找到一个参考
FULL_FLUSH
并注意到
压缩状态被重置,这样,如果以前的压缩数据已损坏或需要随机访问,可以从此点重新启动处理压缩输出数据的充气器。
这听起来不错,因为我可以想象一个重置字节流可能会被视为损坏的数据。所以我重复了我的最小实验:
import java.io._
import java.util.zip._
val bo = new ByteArrayOutputStream()
val zo = new ZipOutputStream(bo)
zo.setLevel(Deflater.FULL_FLUSH)
zo.putNextEntry(new ZipEntry("1"))
zo.write("hello".getBytes())
val bytes1 = bo.toByteArray()
// bytes1: Array[Byte] = Array(80, 75, 3, 4, 20, 0, 8, 8, 8, 0, 84, 75, -8, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 49)
zo.flush()
bo.reset()
zo.write("\nhello".getBytes())
zo.flush()
val bytes2 = bo.toByteArray() // bytes2: Array[Byte] = Array()
所以没有骰子。我在这里的目标是保持内存中的所有内容(因此是字节数组),并通过删除我已经写入uploadpartrequest的字节来降低内存压力,但这确实给事情带来了麻烦,因为我觉得XML文件
必须
因为Excel文件格式实际上是一个zip文件,所以需要进行压缩。我的完整代码显然有点复杂,并且正在使用
Play framework
和scala 2.12.6,
I've put it on github here and added some additional comments if you'd like to look at it or run it.
我知道我可以通过先将Excel文件写入磁盘,然后再将其上载到S3来完成部分上载,但出于我的目的,我希望有一个全内存解决方案,这样我就不必在生成大型临时文件时处理Web服务器上的磁盘空间问题。通过将生成的行保持上传状态,我认为每次上传时内存压力应该保持相当稳定。以下是当前代码在XML文件工作表数据中生成的内容:
…
这对我来说意味着,尽管我的实验没有显示任何字节,但在某个时刻会发生更多的字节,并且会在nuls最终结束后写入文件。
所以…为什么会这样?为什么
ByteArrayOutputStream.reset()
导致在
ZipOutputStream
?如果我不调用.reset(),则
ByteArrayOutputStream
会一直扩展到很大,导致内存不足错误吗?还是我不必担心,因为数据无论如何都会被压缩?