我需要在java中编写一个算法(对于Android应用程序)来读取包含更多文件夹的文件夹,每个文件夹包含图像和音频文件,所以结构是这样的:mainDir/categorySubfolder/myFile1.jpg
我的问题是我需要将存档的大小限制为16mb,并且在运行时,根据需要创建尽可能多的存档以包含我的主mainDir
文件夹中的所有文件。
我在网上尝试了几个例子,我阅读了java文档,但是我无法理解并按照我需要的方式将它们整合在一起。有人之前做过这个或者有链接或示例吗?
我用递归方法解决了文件的读取问题,但我无法编写zip创建的逻辑。
我愿意接受建议或更好的工作实例。
答案 0 :(得分:4)
zip4j是一个很棒的库,可以创建多部分zip文件。
net.lingala.zip4j.core.ZipFile zipFile = new ZipFile("out.zip");
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
zipFile.createZipFileFromFolder("path/to/source/dir", parameters, true, maximum size);
您可以在他们的网站上找到更多示例。
答案 1 :(得分:2)
我使用下面的代码/类来分割和压缩大量/大小的文件。 我在下面测试了这个课程
您必须将 MAX_ZIP_SIZE 的值更改为16(MB)* 1024 * 1024 = 16777216-22(zip标题大小)= 16777194 。
在我的代码中,MAX_ZIP_SIZE设置为3 GB(ZIP has limitation of 4GB on various things)。
final long MAX_ZIP_SIZE = 3221225472L; // 3 GB
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class QDE_ZIP {
public static String createZIP(String directoryPath, String zipFileName, String filesToZip) {
try {
final int BUFFER = 104857600; // 100MB
final long MAX_ZIP_SIZE = 3221225472L; //3 GB
long currentSize = 0;
int zipSplitCount =0;
String files[] = filesToZip.split(",");
if (!directoryPath.endsWith("/")) {
directoryPath = directoryPath + "/";
}
byte fileRAW[] = new byte[BUFFER];
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(directoryPath + zipFileName.toUpperCase()));
ZipEntry zipEntry;
FileInputStream entryFile;
for (String aFile : files) {
zipEntry = new ZipEntry(aFile);
if (currentSize >= MAX_ZIP_SIZE)
{
zipSplitCount ++;
//zipOut.closeEntry();
zipOut.close();
zipOut = new ZipOutputStream(new FileOutputStream(directoryPath + zipFileName.toLowerCase().replace(".zip", "_"+zipSplitCount+".zip").toUpperCase()));
currentSize = 0;
}
zipOut.putNextEntry(zipEntry);
entryFile = new FileInputStream(directoryPath + aFile);
int count;
while ((count = entryFile.read(fileRAW, 0, BUFFER)) != -1) {
zipOut.write(fileRAW, 0, count);
//System.out.println("number of Bytes read = " + count);
}
entryFile.close();
zipOut.closeEntry();
currentSize += zipEntry.getCompressedSize();
}
zipOut.close();
//System.out.println(directory + " -" + zipFileName + " -Number of Files = " + files.length);
} catch (FileNotFoundException e) {
return "FileNotFoundException = " + e.getMessage();
} catch (IOException e) {
return "IOException = " + e.getMessage();
} catch (Exception e) {
return "Exception = " + e.getMessage();
}
return "1";
}
}
我已将所有<em>异常消息作为字符串返回以使用它。这个 我自己的案例与项目有关。
答案 2 :(得分:1)
据我所知How to split a huge zip file into multiple volumes?只是建议到目前为止跟踪存档大小,当它接近某个任意值(应该低于你的最大值)时,它会决定开始一个新的文件。因此,对于16MB的限制,您可以将值设置为10MB并在达到此值时启动新的zip,但是如果您达到9MB并且您的下一个文件压缩到8MB,则最终会得到比您的限制更大的拉链。
该帖子中给出的代码似乎对我不起作用,因为1)它在ZipEntry创建之前得到了大小,所以它总是0和2)它没有写出任何zip :-)如果我错了 - 让我知道。
以下适用于我。为简单起见,我已将它从Wrapper中取出并将其全部放在main(String args [])中。这个代码可以通过很多很多方式得到改进: - )
import java.util.zip.*;
import java.io.*;
public class ChunkedZipTwo {
static final long MAX_LIMIT=10 * 1000 * 1024; //10MB limit - hopefully this
public static void main(String[] args) throws Exception {
String[] files = {"file1", "file2", "file3"};
int i = 0;
boolean needNewFile = false;
long overallSize = 0;
ZipOutputStream out = getOutputStream(i);
byte[] buffer = new byte[1024];
for (String thisFileName: files) {
if (overallSize > MAX_LIMIT) {
out.close();
i++;
out = getOutputStream(i);
overallSize=0;
}
FileInputStream in = new FileInputStream(thisFileName);
ZipEntry ze = new ZipEntry(thisFileName);
out.putNextEntry(ze);
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
out.closeEntry();
in.close();
overallSize+=ze.getCompressedSize();
}
out.close();
}
public static ZipOutputStream getOutputStream(int i) throws IOException {
ZipOutputStream out = new ZipOutputStream(new FileOutputStream("bigfile" + i +".zip"));
out.setLevel(Deflater.DEFAULT_COMPRESSION);
return out;
}
}