java.util.zip – 重新创建目录结构

在尝试使用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());

上面的代码将发出字符串路径/ 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();
    }
  }

这段代码不保存日期,我不知道它将如何反应像符号链接。不会尝试添加目录条目,因此不会包括空目录。

相应的unzip命令:

  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 – 重新创建目录结构 - 代码日志