Jak utworzyć plik zip w Javie


149

Mam dynamiczny plik tekstowy, który pobiera zawartość z bazy danych zgodnie z zapytaniem użytkownika. Muszę zapisać tę zawartość do pliku tekstowego i spakować ją w folderze w serwlecie. Jak mam to zrobić?

Odpowiedzi:


231

Spójrz na ten przykład:

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();

Spowoduje to utworzenie w katalogu głównym D:named, test.zipktóry będzie zawierał jeden plik o nazwie mytext.txt. Oczywiście możesz dodać więcej wpisów zip, a także określić podkatalog w ten sposób:

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

Więcej informacji na temat kompresji w Javie można znaleźć tutaj .


1
Dlaczego te dwie linie: byte[] data = sb.toString().getBytes(); out.write(data, 0, data.length);zawarte w tym przykładzie kodu? Jaki jest ich cel?
Kaadzia

@kdzia, pierwsza linia konwertuje wartość StringBuilder na tablicę bajtów, a druga linia pobiera tę tablicę bajtów i zapisuje ją do ZipEntry w pliku „test.zip”. Te wiersze są konieczne, ponieważ pliki Zip działają z tablicami bajtów, a nie z ciągami.
OrangeWombat

3
Ale ... w powyższym przykładzie, w jaki sposób StringBuilder ma w sobie cokolwiek innego niż „Ciąg testowy”? Też jestem trochę zdezorientowany. Jeśli piszesz sb.toString().getBytes()do pliku ZIP, spodziewam się, że chcesz, aby zawierał bajty archiwizowanego pliku? A może coś mi brakuje?
RobA

3
@RobA niczego nie brakuje. StringBuilder rzeczywiście ma zawierać tekst, który OP uzyskał z jego bazy danych. OP musiałby po prostu zamienić „Ciąg testowy” (w tym cudzysłowy) na coś takiego jak getTextFromDatabase ()
Blueriver

Dzięki, @Blueriver
RobA

143

Java 7 ma wbudowany ZipFileSystem, który może być używany do tworzenia, zapisywania i odczytywania plików z pliku zip.

Dokument Java: dostawca 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); 
}

1
Czy istnieje sposób, aby to działało, jeśli rozszerzenie nie jest .zip? Muszę napisać .fooplik, który jest sformatowany dokładnie tak, jak plik zip, ale z innym rozszerzeniem. Wiem, że mógłbym utworzyć .zipplik i zmienić jego nazwę, ale samo utworzenie go z odpowiednią nazwą byłoby prostsze.
Troy Daniels

2
@TroyDaniels Powyższy przykład działa również z innym rozszerzeniem, ponieważ używa jar:file:prefiksu do tworzenia identyfikatora URI.
Sivabalan

10
Jedynym problemem, który może się tutaj pojawić, jest to, że nie zadziała, jeśli masz katalogi. Na przykład, jeśli masz w pathInZipfilezmiennej „/dir/SomeTextFile.txt” , musisz utworzyć „dir” w archiwum .zip. W tym celu po prostu dodaj następną linię: Files.createDirectories(pathInZipfile.getParent())przed wywołaniem Files.copymetody.
D. Naumovich

jak ustawić poziom kompresji?
cdalxndr

34

Aby napisać plik ZIP, użyj ZipOutputStream. Dla każdego wpisu, który chcesz umieścić w pliku ZIP, tworzysz obiekt ZipEntry. Przekazujesz nazwę pliku do konstruktora ZipEntry; ustawia inne parametry, takie jak data pliku i metoda dekompresji. Jeśli chcesz, możesz zmienić te ustawienia. Następnie wywołujesz metodę putNextEntry obiektu ZipOutputStream, aby rozpocząć pisanie nowego pliku. Wyślij dane pliku do strumienia ZIP. Kiedy skończysz, zadzwoń do closeEntry. Powtórz te czynności dla wszystkich plików, które chcesz przechowywać. Oto szkielet kodu:

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();

22

Oto przykładowy kod do kompresji całego katalogu (w tym plików podrzędnych i podkatalogów), wykorzystujący funkcję drzewa plików w języku 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();
        }
    }
}

Aby z tego skorzystać, po prostu zadzwoń

ZipCompress.compress("target/directoryToCompress");

a otrzymasz plik zip directoryToCompress.zip


4

Spring boot controller, spakuj pliki w katalogu i można je pobrać.

@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();
}

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");
    }
 }    

}

2

Oto jak tworzysz plik zip z pliku źródłowego:

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);
}

1

Pojedynczy plik:

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);
}

Wiele plików:

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);
    }
}

1

Musisz głównie stworzyć dwie funkcje. Pierwsza to writeToZipFile (), a druga to createZipfileForOutPut .... a następnie wywołanie funkcji createZipfileForOutPut ('nazwa pliku .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();
    }
}

0

Jeśli chcesz dekompresować bez oprogramowania, lepiej użyj tego kodu. Inny kod z plikami pdf wysyła błąd przy ręcznym dekompresji

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();
    }

0

Ponieważ zajęło mi to trochę czasu, pomyślałem, że pomocne byłoby opublikowanie mojego rozwiązania przy użyciu 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);            
    }
 }

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());
        }
    }
}

0

Biorąc pod uwagę exportPathi queryResultsjako zmienne typu String, następujący blok tworzy results.zipplik pod exportPathi zapisuje zawartość queryResultsdo results.txtpliku wewnątrz 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);
}

0

Korzystanie z Jeka https://jeka.dev JkPathTree jest dość proste.

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

0

Istnieje inna opcja, korzystając zip4jz https://github.com/srikanth-lingala/zip4j

Tworzenie pliku zip zawierającego jeden plik / Dodawanie pojedynczego pliku do istniejącego pliku ZIP

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

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

Tworzenie pliku ZIP z wieloma plikami / Dodawanie wielu plików do istniejącego pliku ZIP

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

Tworzenie pliku ZIP przez dodanie do niego folderu / Dodanie folderu do istniejącego pliku ZIP

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

Tworzenie pliku ZIP ze strumienia / Dodawanie strumienia do istniejącego pliku ZIP new ZipFile("filename.zip").addStream(inputStream, new ZipParameters());

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.