ZipEntry objects and read/write using ZipInputStreams and ZipOutputStreams which was quite messy and verbose. The zip file system makes working with zip files much easier!
This post shows you how to create a zip file and extract/list its contents, all using a zip file system.
Constructing a zip file system:In order to work with a zip file, you have to construct a "zip file system" first. The method below shows how this is done. You need to pass in a properties map with
create=true if you want the file system to create the zip file if it doesn't exist.
/**
* Returns a zip file system
* @param zipFilename to construct the file system from
* @param create true if the zip file should be created
* @return a zip file system
* @throws IOException
*/
private static FileSystem createZipFileSystem(String zipFilename,
boolean create)
throws IOException {
// convert the filename to a URI
final Path path = Paths.get(zipFilename);
final URI uri = URI.create("jar:file:" + path.toUri().getPath());
final Map<String, String> env = new HashMap<>();
if (create) {
env.put("create", "true");
}
return FileSystems.newFileSystem(uri, env);
}
Once you have a zip file system, you can invoke methods of the java.nio.file.FileSystem, java.nio.file.Path and java.nio.file.Files classes to manipulate the zip file.
Unzipping a Zip File:In order to extract a zip file, you can walk the zip file tree from the root and copy files to the destination directory. Since you are dealing with a zip file system, extracting a directory is exactly the same as copying a directory recursively to another directory. The code below demonstrates this. (Note the use of the try-with-resources statement to close the zip file system automatically when done.)
/**
* Unzips the specified zip file to the specified destination directory.
* Replaces any files in the destination, if they already exist.
* @param zipFilename the name of the zip file to extract
* @param destFilename the directory to unzip to
* @throws IOException
*/
public static void unzip(String zipFilename, String destDirname)
throws IOException{
final Path destDir = Paths.get(destDirname);
//if the destination doesn't exist, create it
if(Files.notExists(destDir)){
System.out.println(destDir + " does not exist. Creating...");
Files.createDirectories(destDir);
}
try (FileSystem zipFileSystem = createZipFileSystem(zipFilename, false)){
final Path root = zipFileSystem.getPath("/");
//walk the zip file tree and copy files to the destination
Files.walkFileTree(root, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
final Path destFile = Paths.get(destDir.toString(),
file.toString());
System.out.printf("Extracting file %s to %s\n", file, destFile);
Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
final Path dirToCreate = Paths.get(destDir.toString(),
dir.toString());
if(Files.notExists(dirToCreate)){
System.out.printf("Creating directory %s\n", dirToCreate);
Files.createDirectory(dirToCreate);
}
return FileVisitResult.CONTINUE;
}
});
}
}
Creating a Zip File:The following method shows how to create a zip file from a list of files. If a directory is passed in, it walks the directory tree and copies files into the zip file system:
/**
* Creates/updates a zip file.
* @param zipFilename the name of the zip to create
* @param filenames list of filename to add to the zip
* @throws IOException
*/
public static void create(String zipFilename, String... filenames)
throws IOException {
try (FileSystem zipFileSystem = createZipFileSystem(zipFilename, true)) {
final Path root = zipFileSystem.getPath("/");
//iterate over the files we need to add
for (String filename : filenames) {
final Path src = Paths.get(filename);
//add a file to the zip file system
if(!Files.isDirectory(src)){
final Path dest = zipFileSystem.getPath(root.toString(),
src.toString());
final Path parent = dest.getParent();
if(Files.notExists(parent)){
System.out.printf("Creating directory %s\n", parent);
Files.createDirectories(parent);
}
Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING);
}
else{
//for directories, walk the file tree
Files.walkFileTree(src, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
final Path dest = zipFileSystem.getPath(root.toString(),
file.toString());
Files.copy(file, dest, StandardCopyOption.REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
final Path dirToCreate = zipFileSystem.getPath(root.toString(),
dir.toString());
if(Files.notExists(dirToCreate)){
System.out.printf("Creating directory %s\n", dirToCreate);
Files.createDirectories(dirToCreate);
}
return FileVisitResult.CONTINUE;
}
});
}
}
}
}
Listing the contents of a zip file:This is the same as extracting a zip file except that instead of copying the files visited, we simply print them out:
/**
* List the contents of the specified zip file
* @param filename
* @throws IOException
* @throws URISyntaxException
*/
public static void list(String zipFilename) throws IOException{
System.out.printf("Listing Archive: %s\n",zipFilename);
//create the file system
try (FileSystem zipFileSystem = createZipFileSystem(zipFilename, false)) {
final Path root = zipFileSystem.getPath("/");
//walk the file tree and print out the directory and filenames
Files.walkFileTree(root, new SimpleFileVisitor<Path>(){
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
print(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
print(dir);
return FileVisitResult.CONTINUE;
}
/**
* prints out details about the specified path
* such as size and modification time
* @param file
* @throws IOException
*/
private void print(Path file) throws IOException{
final DateFormat df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss");
final String modTime= df.format(new Date(
Files.getLastModifiedTime(file).toMillis()));
System.out.printf("%d %s %s\n",
Files.size(file),
modTime,
file);
}
});
}
}
Further Reading:Zip File System Provider
0 comments:
Post a Comment