Cara membuat file zip di Java

149

Saya memiliki file teks dinamis yang mengambil konten dari database sesuai dengan permintaan pengguna. Saya harus menulis konten ini ke dalam file teks dan zip di folder di servlet. Bagaimana saya harus melakukan ini?

Ashish Agarwal
sumber

Jawaban:

231

Lihatlah contoh ini:

StringBuilder sb = new StringBuilder();
sb.append("Test String");

File f = new File("d:\\test.zip");
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f));
ZipEntry e = new ZipEntry("mytext.txt");
out.putNextEntry(e);

byte[] data = sb.toString().getBytes();
out.write(data, 0, data.length);
out.closeEntry();

out.close();

Ini akan membuat zip di root D:bernama test.zipyang akan berisi satu file tunggal yang disebut mytext.txt. Tentu saja Anda dapat menambahkan lebih banyak entri zip dan juga menentukan subdirektori seperti ini:

ZipEntry e = new ZipEntry("folderName/mytext.txt");

Anda dapat menemukan informasi lebih lanjut tentang kompresi dengan Java di sini .

Chris
sumber
1
Mengapa dua baris: byte[] data = sb.toString().getBytes(); out.write(data, 0, data.length);termasuk dalam contoh kode ini? Apa tujuan mereka
Kaadzia
@kdzia, baris pertama mengubah nilai StringBuilder menjadi array byte, dan baris kedua mengambil array byte itu dan menulisnya ke ZipEntry dalam file "test.zip". Baris-baris ini diperlukan karena file Zip berfungsi dengan array byte, bukan string.
OrangeWombat
3
Tapi ... dalam contoh di atas, bagaimana StringBuilder memiliki sesuatu di dalamnya selain "Test String"? Saya sedikit bingung dengan ini juga. Jika Anda menulis sb.toString().getBytes()ke file ZIP, saya berharap Anda ingin itu berisi byte dari file yang Anda zipkan? Atau apakah saya melewatkan sesuatu?
RobA
3
@RobA Anda tidak melewatkan apa pun. StringBuilder memang dimaksudkan untuk memuat teks yang OP dapatkan dari databasenya. OP hanya harus mengganti "Test String" (termasuk tanda kutip) untuk sesuatu seperti getTextFromDatabase ()
Blueriver
Terima kasih, @Blueriver
RobA
143

Java 7 memiliki ZipFileSystem bawaan, yang dapat digunakan untuk membuat, menulis dan membaca file dari file zip.

Java Doc: Penyedia ZipFileSystem

Map<String, String> env = new HashMap<>();
// Create the zip file if it doesn't exist
env.put("create", "true");

URI uri = URI.create("jar:file:/codeSamples/zipfs/zipfstest.zip");

try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
    Path externalTxtFile = Paths.get("/codeSamples/zipfs/SomeTextFile.txt");
    Path pathInZipfile = zipfs.getPath("/SomeTextFile.txt");          
    // Copy a file into the zip file
    Files.copy(externalTxtFile, pathInZipfile, StandardCopyOption.REPLACE_EXISTING); 
}
Sivabalan
sumber
1
Apakah ada cara untuk membuat ini berfungsi jika ekstensi tidak .zip? Saya perlu menulis .foofile, yang diformat persis seperti file zip, tetapi dengan ekstensi yang berbeda. Saya tahu saya bisa membuat .zipfile dan mengganti nama, tetapi hanya membuatnya dengan nama yang tepat akan lebih mudah.
Troy Daniels
2
@TroyDaniels contoh di atas juga berfungsi dengan ekstensi yang berbeda, karena menggunakan jar:file:awalan untuk membuat URI.
Sivabalan
10
Satu-satunya masalah yang dapat muncul di sini adalah bahwa itu tidak akan berfungsi jika Anda memiliki direktori. Jadi, misalnya, jika Anda memiliki "/dir/SomeTextFile.txt" dalam pathInZipfilevariabel, Anda perlu membuat 'dir' di dalam arsip .zip. Untuk ini, tambahkan saja baris berikutnya: Files.createDirectories(pathInZipfile.getParent())sebelum memanggil Files.copymetode.
D. Naumovich
cara mengatur level kompresi?
cdalxndr
34

Untuk menulis file ZIP, Anda menggunakan ZipOutputStream. Untuk setiap entri yang ingin Anda tempatkan ke file ZIP, Anda membuat objek ZipEntry. Anda meneruskan nama file ke konstruktor ZipEntry; itu menetapkan parameter lain seperti tanggal file dan metode dekompresi. Anda dapat mengganti pengaturan ini jika mau. Kemudian, Anda memanggil metode putNextEntry dari ZipOutputStream untuk mulai menulis file baru. Kirim data file ke aliran ZIP. Setelah selesai, panggil closeEntry. Ulangi untuk semua file yang ingin Anda simpan. Berikut ini kerangka kode:

FileOutputStream fout = new FileOutputStream("test.zip");
ZipOutputStream zout = new ZipOutputStream(fout);
for all files
{
    ZipEntry ze = new ZipEntry(filename);
    zout.putNextEntry(ze);
    send data to zout;
    zout.closeEntry();
}
zout.close();
WiseGeek
sumber
22

Berikut adalah contoh kode untuk mengkompres Direktori Utuh (termasuk sub file dan sub direktori), menggunakan fitur walk file tree dari Java NIO.

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipCompress {
    public static void compress(String dirPath) {
        final Path sourceDir = Paths.get(dirPath);
        String zipFileName = dirPath.concat(".zip");
        try {
            final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(zipFileName));
            Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) {
                    try {
                        Path targetFile = sourceDir.relativize(file);
                        outputStream.putNextEntry(new ZipEntry(targetFile.toString()));
                        byte[] bytes = Files.readAllBytes(file);
                        outputStream.write(bytes, 0, bytes.length);
                        outputStream.closeEntry();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Untuk menggunakan ini, telepon saja

ZipCompress.compress("target/directoryToCompress");

dan Anda akan mendapatkan direktori file zipToCompress.zip

Owen Cao
sumber
4

Spring boot controller, zip file dalam direktori, dan dapat diunduh.

@RequestMapping(value = "/files.zip")
@ResponseBody
byte[] filesZip() throws IOException {
    File dir = new File("./");
    File[] filesArray = dir.listFiles();
    if (filesArray == null || filesArray.length == 0)
        System.out.println(dir.getAbsolutePath() + " have no file!");
    ByteArrayOutputStream bo = new ByteArrayOutputStream();
    ZipOutputStream zipOut= new ZipOutputStream(bo);
    for(File xlsFile:filesArray){
        if(!xlsFile.isFile())continue;
        ZipEntry zipEntry = new ZipEntry(xlsFile.getName());
        zipOut.putNextEntry(zipEntry);
        zipOut.write(IOUtils.toByteArray(new FileInputStream(xlsFile)));
        zipOut.closeEntry();
    }
    zipOut.close();
    return bo.toByteArray();
}
Yuiffy
sumber
2
public static void main(String args[])
{
    omtZip("res/", "omt.zip");
}
public static void omtZip(String path,String outputFile)
{
    final int BUFFER = 2048;
    boolean isEntry = false;
    ArrayList<String> directoryList = new ArrayList<String>();
    File f = new File(path);
    if(f.exists())
    {
    try {
            FileOutputStream fos = new FileOutputStream(outputFile);
            ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos));
            byte data[] = new byte[BUFFER];

            if(f.isDirectory())
            {
               //This is Directory
                do{
                    String directoryName = "";
                    if(directoryList.size() > 0)
                    {
                        directoryName = directoryList.get(0);
                        System.out.println("Directory Name At 0 :"+directoryName);
                    }
                    String fullPath = path+directoryName;
                    File fileList = null;
                    if(directoryList.size() == 0)
                    {
                        //Main path (Root Directory)
                        fileList = f;
                    }else
                    {
                        //Child Directory
                        fileList = new File(fullPath);
                    }
                    String[] filesName = fileList.list();

                    int totalFiles = filesName.length;
                    for(int i = 0 ; i < totalFiles ; i++)
                    {
                        String name = filesName[i];
                        File filesOrDir = new File(fullPath+name);
                        if(filesOrDir.isDirectory())
                        {
                            System.out.println("New Directory Entry :"+directoryName+name+"/");
                            ZipEntry entry = new ZipEntry(directoryName+name+"/");
                            zos.putNextEntry(entry);
                            isEntry = true;
                            directoryList.add(directoryName+name+"/");
                        }else
                        {
                            System.out.println("New File Entry :"+directoryName+name);
                            ZipEntry entry = new ZipEntry(directoryName+name);
                            zos.putNextEntry(entry);
                            isEntry = true;
                            FileInputStream fileInputStream = new FileInputStream(filesOrDir);
                            BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, BUFFER);
                            int size = -1;
                            while(  (size = bufferedInputStream.read(data, 0, BUFFER)) != -1  )
                            {
                                zos.write(data, 0, size);
                            }
                            bufferedInputStream.close();
                        }
                    }
                    if(directoryList.size() > 0 && directoryName.trim().length() > 0)
                    {
                        System.out.println("Directory removed :"+directoryName);
                        directoryList.remove(0);
                    }

                }while(directoryList.size() > 0);
            }else
            {
                //This is File
                //Zip this file
                System.out.println("Zip this file :"+f.getPath());
                FileInputStream fis = new FileInputStream(f);
                BufferedInputStream bis = new BufferedInputStream(fis,BUFFER);
                ZipEntry entry = new ZipEntry(f.getName());
                zos.putNextEntry(entry);
                isEntry = true;
                int size = -1 ;
                while(( size = bis.read(data,0,BUFFER)) != -1)
                {
                    zos.write(data, 0, size);
                }
            }               

            //CHECK IS THERE ANY ENTRY IN ZIP ? ----START
            if(isEntry)
            {
              zos.close();
            }else
            {
                zos = null;
                System.out.println("No Entry Found in Zip");
            }
            //CHECK IS THERE ANY ENTRY IN ZIP ? ----START
        }catch(Exception e)
        {
            e.printStackTrace();
        }
    }else
    {
        System.out.println("File or Directory not found");
    }
 }    

}
Dhiral Pandya
sumber
2

Ini adalah bagaimana Anda membuat file zip dari file sumber:

String srcFilename = "C:/myfile.txt";
String zipFile = "C:/myfile.zip";

try {
    byte[] buffer = new byte[1024];
    FileOutputStream fos = new FileOutputStream(zipFile);
    ZipOutputStream zos = new ZipOutputStream(fos);         
    File srcFile = new File(srcFilename);
    FileInputStream fis = new FileInputStream(srcFile);
    zos.putNextEntry(new ZipEntry(srcFile.getName()));          
    int length;
    while ((length = fis.read(buffer)) > 0) {
        zos.write(buffer, 0, length);
    }
    zos.closeEntry();
    fis.close();
    zos.close();            
}
catch (IOException ioe) {
    System.out.println("Error creating zip file" + ioe);
}
cinta hidup
sumber
1

File tunggal:

String filePath = "/absolute/path/file1.txt";
String zipPath = "/absolute/path/output.zip";

try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipPath))) {
    File fileToZip = new File(filePath);
    zipOut.putNextEntry(new ZipEntry(fileToZip.getName()));
    Files.copy(fileToZip.toPath(), zipOut);
}

Banyak file:

List<String> filePaths = Arrays.asList("/absolute/path/file1.txt", "/absolute/path/file2.txt");
String zipPath = "/absolute/path/output.zip";

try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipPath))) {
    for (String filePath : filePaths) {
        File fileToZip = new File(filePath);
        zipOut.putNextEntry(new ZipEntry(fileToZip.getName()));
        Files.copy(fileToZip.toPath(), zipOut);
    }
}
Pavel
sumber
1

Anda harus membuat dua fungsi. Pertama adalah writeToZipFile () dan yang kedua adalah createZipfileForOutPut .... dan kemudian panggil createZipfileForOutPut ('nama file .zip') `...

 public static void writeToZipFile(String path, ZipOutputStream zipStream)
        throws FileNotFoundException, IOException {

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

    File aFile = new File(path);
    FileInputStream fis = new FileInputStream(aFile);
    ZipEntry zipEntry = new ZipEntry(path);
    zipStream.putNextEntry(zipEntry);

    byte[] bytes = new byte[1024];
    int length;
    while ((length = fis.read(bytes)) >= 0) {
        zipStream.write(bytes, 0, length);
    }

    zipStream.closeEntry();
    fis.close();
}

public static void createZipfileForOutPut(String filename) {
    String home = System.getProperty("user.home");
   // File directory = new File(home + "/Documents/" + "AutomationReport");
    File directory = new File("AutomationReport");
    if (!directory.exists()) {
        directory.mkdir();
    }
    try {
        FileOutputStream fos = new FileOutputStream("Path to your destination" + filename + ".zip");
        ZipOutputStream zos = new ZipOutputStream(fos);

        writeToZipFile("Path to file which you want to compress / zip", zos);


        zos.close();
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
Tarpan Patel
sumber
0

Jika Anda ingin dekompresi tanpa perangkat lunak lebih baik gunakan kode ini. Kode lain dengan file pdf mengirimkan kesalahan pada dekompresi secara manual

byte[] buffer = new byte[1024];     
    try
    {   
        FileOutputStream fos = new FileOutputStream("123.zip");
        ZipOutputStream zos = new ZipOutputStream(fos);
        ZipEntry ze= new ZipEntry("file.pdf");
        zos.putNextEntry(ze);
        FileInputStream in = new FileInputStream("file.pdf");
        int len;
        while ((len = in.read(buffer)) > 0) 
        {
            zos.write(buffer, 0, len);
        }
        in.close();
        zos.closeEntry();
        zos.close();
    }
    catch(IOException ex)
    {
       ex.printStackTrace();
    }
cmujica
sumber
0

Karena butuh beberapa saat untuk mengetahuinya, saya pikir akan sangat membantu untuk memposting solusi saya menggunakan Java 7+ ZipFileSystem

 openZip(runFile);

 addToZip(filepath); //loop construct;  

 zipfs.close();

 private void openZip(File runFile) throws IOException {
    Map<String, String> env = new HashMap<>();
    env.put("create", "true");
    env.put("encoding", "UTF-8");
    Files.deleteIfExists(runFile.toPath());
    zipfs = FileSystems.newFileSystem(URI.create("jar:" + runFile.toURI().toString()), env);    
 }

 private void addToZip(String filename) throws IOException {
    Path externalTxtFile = Paths.get(filename).toAbsolutePath();
    Path pathInZipfile = zipfs.getPath(filename.substring(filename.lastIndexOf("results"))); //all files to be stored have a common base folder, results/ in my case
    if (Files.isDirectory(externalTxtFile)) {
        Files.createDirectories(pathInZipfile);
        try (DirectoryStream<Path> ds = Files.newDirectoryStream(externalTxtFile)) {
            for (Path child : ds) {
                addToZip(child.normalize().toString()); //recursive call
            }
        }
    } else {
        // copy file to zip file
        Files.copy(externalTxtFile, pathInZipfile, StandardCopyOption.REPLACE_EXISTING);            
    }
 }
Siraj K
sumber
0
public static void zipFromTxt(String zipFilePath, String txtFilePath) {
    Assert.notNull(zipFilePath, "Zip file path is required");
    Assert.notNull(txtFilePath, "Txt file path is required");
    zipFromTxt(new File(zipFilePath), new File(txtFilePath));
}

public static void zipFromTxt(File zipFile, File txtFile) {
    ZipOutputStream out = null;
    FileInputStream in = null;
    try {
        Assert.notNull(zipFile, "Zip file is required");
        Assert.notNull(txtFile, "Txt file is required");
        out = new ZipOutputStream(new FileOutputStream(zipFile));
        in = new FileInputStream(txtFile);
        out.putNextEntry(new ZipEntry(txtFile.getName()));
        int len;
        byte[] buffer = new byte[1024];
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
            out.flush();
        }
    } catch (Exception e) {
        log.info("Zip from txt occur error,Detail message:{}", e.toString());
    } finally {
        try {
            if (in != null) in.close();
            if (out != null) {
                out.closeEntry();
                out.close();
            }
        } catch (Exception e) {
            log.info("Zip from txt close error,Detail message:{}", e.toString());
        }
    }
}
鄒成立
sumber
0

Diberikan exportPathdan queryResultssebagai variabel String, blok berikut membuat results.zipfile di bawah exportPathdan menulis konten queryResultske results.txtfile di dalam zip.

URI uri = URI.create("jar:file:" + exportPath + "/results.zip");
Map<String, String> env = Collections.singletonMap("create", "true");

try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
  Path filePath = zipfs.getPath("/results.txt");
  byte[] fileContent = queryResults.getBytes();

  Files.write(filePath, fileContent, StandardOpenOption.CREATE);
}
Camilo Silva
sumber
0

Menggunakan Jeka https://jeka.dev JkPathTree, ini cukup mudah.

Path wholeDirToZip = Paths.get("dir/to/zip");
Path zipFile = Paths.get("file.zip");
JkPathTree.of(wholeDirToZip).zipTo(zipFile);
Jerome Angibaud
sumber
0

Ada opsi lain dengan menggunakan zip4jdi https://github.com/srikanth-lingala/zip4j

Membuat file zip dengan file tunggal di dalamnya / Menambahkan file tunggal ke zip yang ada

new ZipFile("filename.zip").addFile("filename.ext"); Atau

new ZipFile("filename.zip").addFile(new File("filename.ext"));

Membuat file zip dengan banyak file / Menambahkan banyak file ke zip yang ada

new ZipFile("filename.zip").addFiles(Arrays.asList(new File("first_file"), new File("second_file")));

Membuat file zip dengan menambahkan folder ke dalamnya / Menambahkan folder ke zip yang ada

new ZipFile("filename.zip").addFolder(new File("/user/myuser/folder_to_add"));

Membuat file zip dari stream / Menambahkan aliran ke zip yang ada new ZipFile("filename.zip").addStream(inputStream, new ZipParameters());

sendon1982
sumber