java.util.zip - Recreating directory structure(转)

简介: include my own version for your reference. We use this one to zip up photos to download so it works with various unzip programs.

 

include my own version for your reference.
We use this one to zip up photos to download so it works with various unzip programs. It preserves the directory structure and timestamps.

public static void createZipFile(File srcDir, OutputStream out,
   boolean verbose) throws IOException {

  List<String> fileList = listDirectory(srcDir);
  ZipOutputStream zout = new ZipOutputStream(out);

  zout.setLevel(9);
  zout.setComment("Zipper v1.2");

  for (String fileName : fileList) {
   File file = new File(srcDir.getParent(), fileName);
   if (verbose)
    System.out.println("  adding: " + fileName);

   // Zip always use / as separator
   String zipName = fileName;
   if (File.separatorChar != '/')
    zipName = fileName.replace(File.separatorChar, '/');
   ZipEntry ze;
   if (file.isFile()) {
    ze = new ZipEntry(zipName);
    ze.setTime(file.lastModified());
    zout.putNextEntry(ze);
    FileInputStream fin = new FileInputStream(file);
    byte[] buffer = new byte[4096];
    for (int n; (n = fin.read(buffer)) > 0;)
     zout.write(buffer, 0, n);
    fin.close();
   } else {
    ze = new ZipEntry(zipName + '/');
    ze.setTime(file.lastModified());
    zout.putNextEntry(ze);
   }
  }
  zout.close();
 }

 public static List<String> listDirectory(File directory)
   throws IOException {

  Stack<String> stack = new Stack<String>();
  List<String> list = new ArrayList<String>();

  // If it's a file, just return itself
  if (directory.isFile()) {
   if (directory.canRead())
    list.add(directory.getName());
   return list;
  }

  // Traverse the directory in width-first manner, no-recursively
  String root = directory.getParent();
  stack.push(directory.getName());
  while (!stack.empty()) {
   String current = (String) stack.pop();
   File curDir = new File(root, current);
   String[] fileList = curDir.list();
   if (fileList != null) {
    for (String entry : fileList) {
     File f = new File(curDir, entry);
     if (f.isFile()) {
      if (f.canRead()) {
       list.add(current + File.separator + entry);
      } else {
       System.err.println("File " + f.getPath()
         + " is unreadable");
       throw new IOException("Can't read file: "
         + f.getPath());
      }
     } else if (f.isDirectory()) {
      list.add(current + File.separator + entry);
      stack.push(current + File.separator + f.getName());
     } else {
      throw new IOException("Unknown entry: " + f.getPath());
     }
    }
   }
  }
  return list;
 }
}

SEPARATOR constant is initialised with the System.getProperty("file.separator") which will give me the OS default file separator.
I would never hardcode a separator since that assumes that your code will only be deployed on a given OS

Don't use File.separator in ZIP. The separator must be "/" according to the spec. If you are on Windows, you must open file as "D:\dir\subdir\file" but ZIP entry must be "dir/subdir/file"

Just go through the source of java.util.zip.ZipEntry. It treats a ZipEntry as directory if its name ends with "/" characters. Just suffix the directory name with "/". Also you need to remove the drive prefix to make it relative.

 

Here is another example (recursive) which also lets you include/exclude the containing folder form the zip:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipUtil {

  private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

  public static void main(String[] args) throws Exception {
    zipFile("C:/tmp/demo", "C:/tmp/demo.zip", true);
  }

  public static void zipFile(String fileToZip, String zipFile, boolean excludeContainingFolder)
    throws IOException {        
    ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));    

    File srcFile = new File(fileToZip);
    if(excludeContainingFolder && srcFile.isDirectory()) {
      for(String fileName : srcFile.list()) {
        addToZip("", fileToZip + "/" + fileName, zipOut);
      }
    } else {
      addToZip("", fileToZip, zipOut);
    }

    zipOut.flush();
    zipOut.close();

    System.out.println("Successfully created " + zipFile);
  }

  private static void addToZip(String path, String srcFile, ZipOutputStream zipOut)
    throws IOException {        
    File file = new File(srcFile);
    String filePath = "".equals(path) ? file.getName() : path + "/" + file.getName();
    if (file.isDirectory()) {
      for (String fileName : file.list()) {             
        addToZip(filePath, srcFile + "/" + fileName, zipOut);
      }
    } else {
      zipOut.putNextEntry(new ZipEntry(filePath));
      FileInputStream in = new FileInputStream(srcFile);

      byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
      int len;
      while ((len = in.read(buffer)) != -1) {
        zipOut.write(buffer, 0, len);
      }

      in.close();
    }
  }
}

 

http://stackoverflow.com/questions/1399126/java-util-zip-recreating-directory-structure

 

相关文章
java高级用法之:JNA中的Structure
前面我们讲到了JNA中JAVA代码和native代码的映射,虽然可以通过TypeMapper来将JAVA中的类型和native中的类型进行映射,但是native中的数据类型都是基础类型,如果native中的数据类型是复杂的struct类型该如何进行映射呢? 不用怕,JNA提供了Structure类,来帮助我们进行这些映射处理。
|
13天前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
95 38
|
11天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
1天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
1天前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
7 3
|
23小时前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
5 1
|
1天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
2天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
1天前
|
安全 Java 编译器
Java多线程编程的陷阱与最佳实践####
【10月更文挑战第29天】 本文深入探讨了Java多线程编程中的常见陷阱,如竞态条件、死锁、内存一致性错误等,并通过实例分析揭示了这些陷阱的成因。同时,文章也分享了一系列最佳实践,包括使用volatile关键字、原子类、线程安全集合以及并发框架(如java.util.concurrent包下的工具类),帮助开发者有效避免多线程编程中的问题,提升应用的稳定性和性能。 ####
18 1
|
5天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
下一篇
无影云桌面