如何在创建它之前在java中估计zip文件的大小
Posted
技术标签:
【中文标题】如何在创建它之前在java中估计zip文件的大小【英文标题】:How to estimate zip file size in java before creating it 【发布时间】:2010-08-26 06:05:29 【问题描述】:我有一个要求,我必须从可用文件列表中创建一个 zip 文件。这些文件有不同的类型,如 txt、pdf、xml 等。我正在使用 java util 类来做。
这里的要求是保持最大文件大小为 5 MB。我应该根据时间戳从列表中选择文件,将文件添加到 zip 中,直到 zip 文件大小达到 5 mb。我应该跳过剩下的文件。
请让我知道 java 中有没有一种方法可以在不创建实际文件的情况下提前估计 zip 文件的大小?
或者有没有其他方法可以解决这个问题
【问题讨论】:
【参考方案1】:将您的 ZipOutputStream 包装成个性化的 OutputStream,在此处命名为 YourOutputStream。
YourOutputStream 的构造函数将创建另一个ZipOutputStream
(zos2),它包装一个新的 ByteArrayOutputStream
(baos)public YourOutputStream(ZipOutputStream zos, int maxSizeInBytes)
当你想用YourOutputStream
写一个文件时,它会先写在zos2上public void writeFile(File file) throws ZipFileFullException
public void writeFile(String path) throws ZipFileFullException
等等……
如果baos.size()
在maxSizeInBytes
之下
在zos1中写入文件
其他
关闭 zos1、baos、zos2 并抛出异常。对于异常,我想不出已经存在的,如果有,使用它,否则创建你自己的 IOException ZipFileFullException。
您需要两个 ZipOutputStream,一个用于写入驱动器,一个用于检查您的内容是否超过 5MB。
编辑:事实上我检查过,you can't remove a ZipEntry easily。
http://download.oracle.com/javase/6/docs/api/java/io/ByteArrayOutputStream.html#size()
【讨论】:
感谢大家的帮助。由于我只需要粗略的大小并且能够找出我们使用的大多数文件类型的压缩比,因此我使用了 Nate 建议的那种。再次感谢大家【参考方案2】:+1 for Colin Herbert:逐个添加文件,备份上一步或删除最后一个文件(如果存档太大)。我只是想补充一些细节:
预测太不可靠了。 PDF 可以包含未压缩的文本,压缩到原始文件的 30%,或者它包含已经压缩的文本和图像,压缩到 80%。您需要检查整个 PDF 的可压缩性,基本上必须压缩它们。
您可以尝试统计预测,但这可以减少尝试失败的次数,但您仍然必须实施上述建议。先用更简单的实现,看看够不够。
或者,单独压缩文件,然后选择捆绑在一起时不超过 5 MB 的文件。如果解包也是自动的,您可以将 zip 文件绑定到一个未压缩的 zip 文件中。
【讨论】:
如果实际上这不起作用,您可以拥有一个超过 5MB 的文件,其中仅包含“aaaa...”,它会被压缩到足以放入 zip 文件中。【参考方案3】:还有更好的选择。创建一个只计算写入字节数的虚拟LengthOutputStream
:
public class LengthOutputStream extends OutputStream
private long length = 0L;
@Override
public void write(int b) throws IOException
length++;
public long getLength()
return length;
您只需将LengthOutputStream
连接到ZipOutputStream
:
public static long sizeOfZippedDirectory(File dir) throws FileNotFoundException, IOException
try (LengthOutputStream sos = new LengthOutputStream();
ZipOutputStream zos = new ZipOutputStream(sos);)
... // Add ZIP entries to the stream
return sos.getLength();
LengthOutputStream
对象计算压缩流的字节数,但不存储任何内容,因此没有文件大小限制。此方法可提供准确的大小估计,但几乎与创建 ZIP 文件一样慢。
【讨论】:
【参考方案4】:我认为没有任何方法可以估计将创建的 zip 的大小,因为 zip 是作为流处理的。此外,除非您实际压缩它,否则在技术上无法预测创建的压缩格式的大小。
【讨论】:
【参考方案5】:我曾在一个输入类型已知的项目中这样做过。我们知道,一般来说,我们的数据压缩率约为 5:1(全是文本)。所以,我会检查文件大小并除以 5...
在这种情况下,这样做的目的是检查文件是否可能低于特定大小。我们只需要一个粗略的估计。
话虽如此,我注意到像 7zip 这样的 zip 应用程序会创建一个特定大小的 zip 文件(如 CD),然后在达到限制时将 zip 拆分为一个新文件。你可以看看那个源代码。我之前实际上已经在代码中使用过该应用程序的命令行版本。他们有一个你也可以使用的库。但不确定它与 Java 的集成效果如何。
对于它的价值,我还使用了一个名为 SharpZipLib 的库。非常好。我想知道它是否有 Java 端口。
【讨论】:
【参考方案6】:也许您可以每次添加一个文件,直到达到 5MB 的限制,然后丢弃最后一个文件。像 @Gopi 一样,我认为没有任何方法可以在不实际压缩文件的情况下估计它。
当然,文件大小不会增加(或者可能一点点,因为 zip 标头?),所以至少你有一个“最坏情况”的估计。
【讨论】:
【参考方案7】:只是想分享我们如何实现手动方式
int maxSizeForAllFiles = 70000; // Read from property
int sizePerFile = 22000; // Red from property
/**
* Iterate all attachment list to verify if ZIP is required
*/
for (String attachFile : inputAttachmentList)
File file = new File(attachFile);
totalFileSize += file.length();
/**
* if ZIP required ??? based on the size
*/
if (file.length() >= sizePerFile)
toBeZipped = true;
logger.info("File: "
+ attachFile
+ " Size: "
+ file.length()
+ " File required to be zipped, MAX allowed per file: "
+ sizePerFile);
break;
/**
* Check if all attachments put together cross MAX_SIZE_FOR_ALL_FILES
*/
if (totalFileSize >= maxSizeForAllFiles)
toBeZipped = true;
if (toBeZipped)
// Zip Here iterating all attachments
【讨论】:
以上是关于如何在创建它之前在java中估计zip文件的大小的主要内容,如果未能解决你的问题,请参考以下文章
如何在不实际序列化对象的情况下估计 Java 中对象的序列化大小?