Java 压缩包含子文件夹的文件夹
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3961087/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Zipping a folder which contains subfolders
提问by LGAP
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.
我正在尝试压缩包含子文件夹的文件夹。尝试压缩名为 10-18-2010_4D 的文件夹。上述程序以以下异常结束。请告知如何清除该问题。
java.io.FileNotFoundException: Output-18-2010_4DD (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)
采纳答案by dogbane
回答by Bozho
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)
任务类可以在这里找到:(org.apache.tools.ant.taskdefs.Zip
以编程方式使用)
回答by dan
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);
}
}
回答by Bane
Here's the code for creating the ZIP archive. Created archive preserves original directory structure (if any).
这是用于创建 ZIP 存档的代码。创建的存档保留原始目录结构(如果有)。
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();
}
回答by Tzach Solomon
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();
}
}
}
}
回答by Charlweed
Java 7+ version, using Path, FileVisitor and AutoCloseable interfaces. To use this example, just call zipWalking(sourceDir,targetZipFile);
Java 7+ 版本,使用 Path、FileVisitor 和 AutoCloseable 接口。要使用此示例,只需调用 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();
}
}
回答by Pauliman
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
这是我在努力压缩一段时间后想出的另一个例子。它与其他示例类似,但我在那些我认为需要更多解释的地方添加了很多注释。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