Java:递归地将文件添加到zip文件但没有完整路径

时间:2016-01-03 11:32:38

标签: java

我正在尝试将zip文件中的文件夹放在以下结构中:

Folder structure:

myFolder
 |-file1.txt
 |-file2.txt
 |-folder172
    |-file817.txt
    |-file818.txt
 ...

Supposed structure inside ZipFile:

file1.txt
file2.txt
folder172
 |-file817.txt
 |-file818.txt

这是我的代码:

public static void writeZip(String path) throws IOException{

    FileOutputStream fos = new FileOutputStream(path+File.separator+"atest.zip");
    ZipOutputStream zos = new ZipOutputStream(fos);

    try {
        Files.walk(Paths.get(path)).filter(Files::isRegularFile).forEach((string) -> addToZipFile(string.toString(),zos));
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    zos.close();
    fos.close();



}


public static void addToZipFile(String fileName, ZipOutputStream zos) throws IOException {

    System.out.println("Writing '" + fileName + "' to zip file");

    File file = new File(fileName);
    FileInputStream fis = null;

    fis = new FileInputStream(file);

    ZipEntry zipEntry = new ZipEntry(fileName);

    zos.putNextEntry(zipEntry);


    byte[] bytes = new byte[1024];
    int length;

    while ((length = fis.read(bytes)) >= 0) {
        zos.write(bytes, 0, length);
    }
    zos.closeEntry();
    fis.close();

}

现在问题是,当我调用writeZip("/home/arthur/.grutil/");时,我在zip文件中得到以下结构:

home
 |-arthur
    |-.grutil
       |-file1.txt
       |-file2.txt
       |-folder172
          |-file817.txt
          |-file818.txt
   ...

我如何更改我的代码以获得所谓的结构(如上所述)而不是具有完整路径的结构&#39; /home/arthur/.grutil/ ...&#39;?< / p>

1 个答案:

答案 0 :(得分:2)

虽然这可以用古代的ZipOutputStream来完成,但我建议不要这样做。

将Zip存档视为文件中的压缩文件系统比将字节流更直观。因此,Java提供ZipFileSystem

所以您需要做的就是将Zip打开为FileSystem,然后手动复制文件。

有几个陷阱:

  1. 您只需要复制文件,目录需要创建
  2. NIO API不支持不同文件系统中的relativize等操作(原因应该很明显),所以您需要自己动手。
  3. 以下是一些简单的方法:

    /**
     * This creates a Zip file at the location specified by zip
     * containing the full directory tree rooted at contents
     *
     * @param zip      the zip file, this must not exist
     * @param contents the root of the directory tree to copy
     * @throws IOException, specific exceptions thrown for specific errors
     */
    public static void createZip(final Path zip, final Path contents) throws IOException {
        if (Files.exists(zip)) {
            throw new FileAlreadyExistsException(zip.toString());
        }
        if (!Files.exists(contents)) {
            throw new FileNotFoundException("The location to zip must exist");
        }
        final Map<String, String> env = new HashMap<>();
        //creates a new Zip file rather than attempting to read an existing one
        env.put("create", "true");
        // locate file system by using the syntax
        // defined in java.net.JarURLConnection
        final URI uri = URI.create("jar:file:/" + zip.toString().replace("\\", "/"));
        try (final FileSystem zipFileSystem = FileSystems.newFileSystem(uri, env);
             final Stream<Path> files = Files.walk(contents)) {
            final Path root = zipFileSystem.getPath("/");
            files.forEach(file -> {
                try {
                    copyToZip(root, contents, file);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
    
    /**
     * Copy a specific file/folder to the zip archive
     * If the file is a folder, create the folder. Otherwise copy the file
     *
     * @param root     the root of the zip archive
     * @param contents the root of the directory tree being copied, for relativization
     * @param file     the specific file/folder to copy
     */
    private static void copyToZip(final Path root, final Path contents, final Path file) throws IOException {
        final Path to = root.resolve(contents.relativize(file).toString());
        if (Files.isDirectory(file)) {
            Files.createDirectories(to);
        } else {
            Files.copy(file, to);
        }
    }