public static void main(String argv[]) {
try {
String date = new java.text.SimpleDateFormat("MM-dd-yyyy")
.format(new java开发者_运维百科.util.Date());
File inFolder = new File("Output/" + date + "_4D");
File outFolder = new File("Output/" + date + "_4D" + ".zip");
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(
new FileOutputStream(outFolder)));
BufferedInputStream in = null;
byte[] data = new byte[1000];
String files[] = inFolder.list();
for (int i = 0; i < files.length; i++) {
in = new BufferedInputStream(new FileInputStream(
inFolder.getPath() + "/" + files[i]), 1000);
out.putNextEntry(new ZipEntry(files[i]));
int count;
while ((count = in.read(data, 0, 1000)) != -1) {
out.write(data, 0, count);
}
out.closeEntry();
}
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I'm trying to zip a folder which contains subfolders. Trying to zip the folder named 10-18-2010_4D.The above program ends with the following exception. Please advise on how to clear the issue.
java.io.FileNotFoundException: Output\10-18-2010_4D\4D (Access is denied)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)
at ZipFile.main(ZipFile.java:17)
Here's the code for creating the ZIP archive. Created archive preserves original directory structure (if any).
public static void addDirToZipArchive(ZipOutputStream zos, File fileToZip, String parrentDirectoryName) throws Exception {
if (fileToZip == null || !fileToZip.exists()) {
return;
}
String zipEntryName = fileToZip.getName();
if (parrentDirectoryName!=null && !parrentDirectoryName.isEmpty()) {
zipEntryName = parrentDirectoryName + "/" + fileToZip.getName();
}
if (fileToZip.isDirectory()) {
System.out.println("+" + zipEntryName);
for (File file : fileToZip.listFiles()) {
addDirToZipArchive(zos, file, zipEntryName);
}
} else {
System.out.println(" " + zipEntryName);
byte[] buffer = new byte[1024];
FileInputStream fis = new FileInputStream(fileToZip);
zos.putNextEntry(new ZipEntry(zipEntryName));
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
fis.close();
}
}
Don't forget to close output streams after calling this method. Here's the example:
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("C:\\Users\\vebrpav\\archive.zip");
ZipOutputStream zos = new ZipOutputStream(fos);
addDirToZipArchive(zos, new File("C:\\Users\\vebrpav\\Downloads\\"), null);
zos.flush();
fos.flush();
zos.close();
fos.close();
}
Simply you can use this library Zeroturnaround Zip library
Then you will zip your folder just a one line:
ZipUtil.pack(new File("D:\\sourceFolder\\"), new File("D:\\generatedZipFile.zip"));
You need to check if the file is a directory because you can't pass directories to the zip method.
Take a look at this page which shows how you can recursively zip a given directory.
I would include the ant task for zipping - it is way easier to work with.
The task class can be found here: org.apache.tools.ant.taskdefs.Zip
(use it programatically)
private void zipFiles (ArrayList listWithFiles, String zipName) {
try {
byte[] buffer = new byte[1024];
// create object of FileOutputStream
FileOutputStream fout = new FileOutputStream(zipName);
// create object of ZipOutputStream from FileOutputStream
ZipOutputStream zout = new ZipOutputStream(fout);
for (String currentFile : listWithFiles) {
// create object of FileInputStream for source file
FileInputStream fin = new FileInputStream(currentFile);
// add files to ZIP
zout.putNextEntry(new ZipEntry(currentFile ));
// write file content
int length;
while ((length = fin.read(buffer)) > 0) {
zout.write(buffer, 0, length);
}
zout.closeEntry();
// close the InputStream
fin.close();
}
// close the ZipOutputStream
zout.close();
} catch (IOException ioe) {
System.out.println("IOException :" + ioe);
}
}
Here is what I've written. This example keeps the structure of the files and by that, avoid the duplicate entry exception.
/**
* Compress a directory to ZIP file including subdirectories
* @param directoryToCompress directory to zip
* @param outputDirectory where to place the compress file
*/
public void zipDirectory(File directoryToCompress, File outputDirectory){
try {
FileOutputStream dest = new FileOutputStream(new File(outputDirectory, directoryToCompress.getName() + ".zip"));
ZipOutputStream zipOutputStream = new ZipOutputStream(dest);
zipDirectoryHelper(directoryToCompress, directoryToCompress, zipOutputStream);
zipOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
private void zipDirectoryHelper(File rootDirectory, File currentDirectory, ZipOutputStream out) throws Exception {
byte[] data = new byte[2048];
File[] files = currentDirectory.listFiles();
if (files == null) {
// no files were found or this is not a directory
} else {
for (File file : files) {
if (file.isDirectory()) {
zipDirectoryHelper(rootDirectory, file, out);
} else {
FileInputStream fi = new FileInputStream(file);
// creating structure and avoiding duplicate file names
String name = file.getAbsolutePath().replace(rootDirectory.getAbsolutePath(), "");
ZipEntry entry = new ZipEntry(name);
out.putNextEntry(entry);
int count;
BufferedInputStream origin = new BufferedInputStream(fi,2048);
while ((count = origin.read(data, 0 , 2048)) != -1){
out.write(data, 0, count);
}
origin.close();
}
}
}
}
Here is another example that I came up with after struggeling with zipping for some time. It's similar to the other examples but I added a lot of comments in those areas where I thought more explanation was needed. Java SE9
public final class Zipper {
private static FileOutputStream fos;
private static ZipOutputStream zos;
private static BufferedOutputStream bos;
private static ZipEntry entry;
private static FileInputStream fis;
private static BufferedInputStream bis;
private static final int BUFFER_CAPACITY = 1024;
private static byte[] buffer; // The actual buffer a byte array with a capacity of 1024
private static int buffer_size; // The buffer size (not capacity) used by the read()-method of the BufferedInputStream.
/**
* This is the method to start things with.
* @param source File object referencing the unzipped folder to be turned into a zip file.
* @param target File object referencing the yet to be written zip-file that will contain the entire folder (source)
* @param compression_level The level of compression expressed by an int-value. See Deflater class for constant details.
* @return True if everything worked as planned, false if not.
*/
public static boolean zipFile(File source, File target, int compression_level) {
boolean check = true;
try {
fos = new FileOutputStream(target); // Primary output stream connecting to the file to be zipped
zos = new ZipOutputStream(fos); // Secondary zip-stream that writes zipped data to the primary stream
zos.setMethod(ZipOutputStream.DEFLATED);// Method of compression this expression is the default setting
zos.setLevel(compression_level); // Sets the level of compression 0 = no compression
bos = new BufferedOutputStream(zos);// Secondary buffered stream that writes to the Zip-stream
} catch (IOException e) {
System.out.println("Zipper.zipFile() says: " + e);
check = false;
}
if (source.isDirectory()) {
buffer = new byte[BUFFER_CAPACITY];
if (manageFolder(source, ""))//Because of recursive character of the called method the second argument
//must be empty, if the method is called for the first time.
check = false;
} else {
buffer = new byte[BUFFER_CAPACITY];
if (writeFileToZipStream(source, ""))
check = false;
}
try {
zos.finish();
bos.close();
zos.close();
fos.close();
} catch (Exception e) {
System.out.println("While closing streams (final), the following happend: " + e);
}
return true;
} // end of zipFile()
/**
* Receives a folder path and extracts all content (files and subfolders) into a File[] if it then detects
* another folder it calls itself and passes on the new folder path as the first parameter.
* The second parameter is the relative path/name of the current sub-folder
* seen from the perspective of the root or base folder. As folders get written as part of a file, you don't have to
* care for folders, just make sure your files carry the all folders in their file name and these file names
* are passed on to the ZipEntry.
* @param source_folder The current folder to be written to the ZipOutputStream. Absolute folder
* @param name The relative path to the current folder. Empty at first and building up
* as it goes deeper down the folder hierarchy.
* @return True if everything worked as planned, false if not.
*/
private static boolean manageFolder(File source_folder, String name) {
boolean check = true;
File[] all_files = source_folder.listFiles();//Array containing all files and folders of the current folder tier
for (File single_file : all_files) { // Iteration over all the files and folders
if (single_file.isDirectory()) { // If a sub-folder is encountered ...
manageFolder(single_file, name + File.separator + single_file.getName()); // Call the current method with: Arg1 absolute path to current sub-folder, Arg2 name of current folder(s) + "/" + name of current sub-folder
} else { // If a simple file is encountered
if (!writeFileToZipStream(single_file, name +File.separator + single_file.getName())) // Call the writeFileToZip()-method with Arg1: absolute path to source file, Arg2 subfolder(s) + "/" + file name
check = false;
}
}
return check;
} // end of manageFolder()
/**
* Writes a file to the BufferedOutputStream.
* @param source_file Absloute path a file in the source folder
* @param entry_name Relative path to a file starting at the root or base folder level.
* @return True if everything worked as planned, false if not.
*/
private static boolean writeFileToZipStream(File source_file, String entry_name) {
entry_name = entry_name.equals("") ? entry_name : entry_name.substring(1); // Deletes initial "\"
boolean check = true;
try {
fis = new FileInputStream(source_file);
bis = new BufferedInputStream(fis, BUFFER_CAPACITY);
entry = new ZipEntry(entry_name.equals("") ? source_file.getName() : entry_name); //Reacts to an empty argument
zos.putNextEntry(entry);
while ((buffer_size = bis.read(buffer, 0, BUFFER_CAPACITY)) != -1) {
bos.write(buffer, 0, buffer_size);
}
} catch (IOException e) {
System.out.println("Zipper.writeFileToZipStream() says: " + e);
check = false;
}
try {
bos.flush(); // Don't forget to flush the stream .
zos.closeEntry(); // Close every entry before you open a new one.
bis.close(); // The input streams will be attached to every file, so it must be closed after each run.
fis.close(); // Same here.
} catch (IOException e) {
System.out.println("While closing streams (file), the following happend: " + e);
}
return check;
} // end of writeImageFileToZioStream()
} // end of class
Java 7+ version, using Path, FileVisitor and AutoCloseable interfaces. To use this example, just call zipWalking(sourceDir,targetZipFile);
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import static java.nio.file.FileVisitResult.CONTINUE;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
*
* @author deftDeveloper
*/
public class ZippingVisitor extends SimpleFileVisitor<Path> implements java.lang.AutoCloseable {
private static final Logger LOG = Logger.getLogger(ZippingVisitor.class.getName());
public static final int BUFFER_SIZE = 4096;
private final Path _source;
private final Path _target;
private final FileOutputStream _fos;
private final ZipOutputStream _zos;
public static void zipWalking(Path source, Path target) {
try (ZippingVisitor zippingVisitor = new ZippingVisitor(source, target)) {
Files.walkFileTree(source, zippingVisitor);
} catch (IOException ioe) {
LOG.log(Level.SEVERE, null, ioe);
}
}
public ZippingVisitor(Path source, Path target) throws FileNotFoundException {
this._source = source;
this._target = target;
_fos = new FileOutputStream(_target.toFile());
_zos = new ZipOutputStream(_fos);
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!Files.exists(file)) {
throw new IOException("File " + file.toString() + " not found.");
}
Path zipEntryPath = _source.relativize(file);
LOG.log(Level.FINE, zipEntryPath.toString());
byte[] buffer = new byte[BUFFER_SIZE];
try (FileInputStream fis = new FileInputStream(file.toFile())) {
_zos.putNextEntry(new ZipEntry(zipEntryPath.toString()));
int length;
while ((length = fis.read(buffer)) > 0) {
_zos.write(buffer, 0, length);
}
_zos.closeEntry();
} catch (IOException ioe) {
LOG.log(Level.SEVERE, null, ioe);
}
return CONTINUE;
}
@Override
public void close() throws IOException {
_zos.close();
_fos.close();
}
}
The below code maintains the directory structure of the sourceFolder inside zip file. Also it can traverse upto depth of Integer.MAX_VALUE.
I have found that using Files.walkFileTree(..) is much simpler and cleaner than Files.walk(..)
Disclaimer: I haven't customized the answer as per the code pasted in the question. This was my use-case to simply zip a directory containing sub-directories while maintaining the directory structure.
Driver code: createZipOfFolder("results/folder")
Output: results/folder.zip
Implementation:
public void createZipOfFolder(@NonNull String sourceFolderName) {
Path sourceFolderPath = Paths.get(sourceFolderName);
Path zipFilePath = Paths.get(sourceFolderPath + ".zip");
// This baseFolderPath is upto the parent folder of sourceFolder.
// Used to remove nesting of parent folder inside zip
Path baseFolderPath = Paths.get(sourceFolderName.substring(0,
sourceFolderName.indexOf(sourceFolderPath.getFileName().toString())));
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilePath.toFile()))) {
Files.walkFileTree(sourceFolderPath, new SimpleFileVisitor<>() {
@Override
public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
System.out.println("Adding Dir: " + dir);
// Ending slash is required to persist the folder as folder else it persists as file
zos.putNextEntry(new ZipEntry(baseFolderPath.relativize(dir) + "/"));
zos.closeEntry();
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
System.out.println("Adding file: " + file);
zos.putNextEntry(new ZipEntry(baseFolderPath.relativize(file).toString()));
Files.copy(file, zos);
zos.closeEntry();
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
精彩评论