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

标签 java directory zip structure

在尝试使用 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/

相关文章:

iphone - 在 iPhone 上创建目录

php - 任何人都知道 PHP 系统命令行 zip 的一个很好的例子

java - 更改java文件

java - Quickbooks API - 如何使用存储的银行帐户创建费用

java - 按钮与底部对齐,从 ImageView 中隐藏

Eclipse 在 Package Explorer 中将包 View 更改为文件夹 View ?

java - LWJGL:将 "curve"应用于景观

ios - 如何以编程方式打开带有 myapp 文件夹的默认文件应用程序?

iphone - iOS iphone 解压缩跨区(多卷).7z 或 .zip 文件

swift - Apple TV 上带有 swift 的 .XZ 文件