在尝试使用 java.util.zip
压缩文件时,我遇到了很多问题,其中大部分我都解决了。现在我终于得到了一些输出,我很难获得“正确”的输出。我有一个提取的 ODT 文件(目录更适合描述),我对其进行了一些修改。现在我想压缩该目录以重新创建 ODT 文件结构。压缩目录并将其重命名为以 .odt 结尾可以正常工作,因此应该没有问题。
主要问题是我丢失了目录的内部结构。一切都变得“平坦”,我似乎没有找到保留原始多层结构的方法。我将不胜感激,因为我似乎无法找到问题所在。
以下是相关的代码片段:
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
FILEPATH.substring(0, FILEPATH.lastIndexOf(SEPARATOR) + 1).concat("test.zip")));
compressDirectory(TEMPARCH, out);
SEPARATOR
是系统文件分隔符,FILEPATH
是原始 ODT 的文件路径,我将覆盖它,但出于测试目的,这里没有这样做。我只是在同一目录中写入 test.zip 文件。
private void compressDirectory(String directory, ZipOutputStream out) throws IOException
{
File fileToCompress = new File(directory);
// list contents.
String[] contents = fileToCompress.list();
// iterate through directory and compress files.
for(int i = 0; i < contents.length; i++)
{
File f = new File(directory, contents[i]);
// testing type. directories and files have to be treated separately.
if(f.isDirectory())
{
// add empty directory
out.putNextEntry(new ZipEntry(f.getName() + SEPARATOR));
// initiate recursive call
compressDirectory(f.getPath(), out);
// continue the iteration
continue;
}else{
// prepare stream to read file.
FileInputStream in = new FileInputStream(f);
// create ZipEntry and add to outputting stream.
out.putNextEntry(new ZipEntry(f.getName()));
// write the data.
int len;
while((len = in.read(data)) > 0)
{
out.write(data, 0, len);
}
out.flush();
out.closeEntry();
in.close();
}
}
}
包含要压缩的文件的目录位于用户空间中的某个位置,而不是与生成的文件位于同一目录中。我认为这可能会很麻烦,但我真的不知道怎么做。我还认为问题可能在于使用相同的流进行输出,但我又看不出如何。我在一些示例和教程中看到他们使用 getPath()
而不是 getName()
但改变它会给我一个空的 zip 文件。
最佳答案
URI类对于使用相对路径很有用。
File mydir = new File("C:\\mydir");
File myfile = new File("C:\\mydir\\path\\myfile.txt");
System.out.println(mydir.toURI().relativize(myfile.toURI()).getPath());
以上代码将发出字符串path/myfile.txt
。
为了完整起见,这里是一个用于归档目录的 zip
方法:
public static void zip(File directory, File zipfile) throws IOException {
URI base = directory.toURI();
Deque<File> queue = new LinkedList<File>();
queue.push(directory);
OutputStream out = new FileOutputStream(zipfile);
Closeable res = out;
try {
ZipOutputStream zout = new ZipOutputStream(out);
res = zout;
while (!queue.isEmpty()) {
directory = queue.pop();
for (File kid : directory.listFiles()) {
String name = base.relativize(kid.toURI()).getPath();
if (kid.isDirectory()) {
queue.push(kid);
name = name.endsWith("/") ? name : name + "/";
zout.putNextEntry(new ZipEntry(name));
} else {
zout.putNextEntry(new ZipEntry(name));
copy(kid, zout);
zout.closeEntry();
}
}
}
} finally {
res.close();
}
}
此代码不保留日期,我不确定它会如何对符号链接(symbolic link)之类的内容使用react。不会尝试添加目录条目,因此不会包含空目录。
对应的解压
命令:
public static void unzip(File zipfile, File directory) throws IOException {
ZipFile zfile = new ZipFile(zipfile);
Enumeration<? extends ZipEntry> entries = zfile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File file = new File(directory, entry.getName());
if (entry.isDirectory()) {
file.mkdirs();
} else {
file.getParentFile().mkdirs();
InputStream in = zfile.getInputStream(entry);
try {
copy(in, file);
} finally {
in.close();
}
}
}
}
他们所依赖的实用方法:
private static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
while (true) {
int readCount = in.read(buffer);
if (readCount < 0) {
break;
}
out.write(buffer, 0, readCount);
}
}
private static void copy(File file, OutputStream out) throws IOException {
InputStream in = new FileInputStream(file);
try {
copy(in, out);
} finally {
in.close();
}
}
private static void copy(InputStream in, File file) throws IOException {
OutputStream out = new FileOutputStream(file);
try {
copy(in, out);
} finally {
out.close();
}
}
缓冲区大小完全是任意的。
关于java.util.zip - 重新创建目录结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1399126/