【问题标题】:How to extract specific file in a zip file in java如何在java中提取zip文件中的特定文件
【发布时间】:2015-11-17 16:29:47
【问题描述】:

我需要在系统中向客户提供 zip 文件的视图,并允许客户下载选择的文件。

  1. 解析压缩文件并显示在网页上。并记住后端的每个 zipentry 位置(例如 file1 从字节 100 宽度长度 1024 字节开始)。
  2. 当客户点击下载按钮时下载指定文件。

现在我已经记住了所有的 zipentry 位置,但是是否有 java zip 工具可以解压缩 zip 文件的指定位置? API 就像 unzip(file, long entryStart, long entryLength);

【问题讨论】:

标签: java zip


【解决方案1】:

您可以使用以下代码从 zip 中提取特定文件:-

public static void main(String[] args) throws Exception{
        String fileToBeExtracted="fileName";
        String zipPackage="zip_name_with_full_path";
        OutputStream out = new FileOutputStream(fileToBeExtracted);
        FileInputStream fileInputStream = new FileInputStream(zipPackage);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream );
        ZipInputStream zin = new ZipInputStream(bufferedInputStream);
        ZipEntry ze = null;
        while ((ze = zin.getNextEntry()) != null) {
            if (ze.getName().equals(fileToBeExtracted)) {
                byte[] buffer = new byte[9000];
                int len;
                while ((len = zin.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }
                out.close();
                break;
            }
        }
        zin.close();

    }

另请参考此链接:How to extract a single file from a remote archive file?

【讨论】:

  • 它只适用于一种情况,即在每个条目头中保存了 compressSize 和原始条目大小。但是有些 zip 文件没有将这些信息保存在条目头中,在这种情况下,zin.getNextEntry() 会读取之前的条目数据以到达下一个条目而不是寻找下一个条目,因此它会执行缓慢。
【解决方案2】:

你可以这样试试:

ZipFile zf = new ZipFile(file);
try {
  InputStream in = zf.getInputStream(zf.getEntry("file.txt"));
  // ... read from 'in' as normal
} finally {
  zf.close();
}

我没有尝试过,但在 Java 7 ZipFileSystem 中,您可以尝试这样从 zip 文件中提取 file.TXT 文件。

Path zipfile = Paths.get("/samples/ziptest.zip");
FileSystem fs = FileSystems.newFileSystem(zipfile, env, null);
final Path root = fs.getPath("/file.TXT");

【讨论】:

    【解决方案3】:

    使用 Java 7 的 NIO2 可以在不弄乱字节数组或输入流的情况下做到这一点:

    public void extractFile(Path zipFile, String fileName, Path outputFile) throws IOException {
        // Wrap the file system in a try-with-resources statement
        // to auto-close it when finished and prevent a memory leak
        try (FileSystem fileSystem = FileSystems.newFileSystem(zipFile, null)) {
            Path fileToExtract = fileSystem.getPath(fileName);
            Files.copy(fileToExtract, outputFile);
        }
    }
    

    【讨论】:

      【解决方案4】:

      要使用 FileSystems.newFileSystem,您需要使用 URI.create 创建第一个参数

      您需要指定正确的协议。 “罐子:文件:”

      另外:你需要一个带有属性的 Map():

      map.put("create","true"); (or "false" to extract)
      extract("/tmp","photos.zip","tiger.png",map)
      
      void extract(String path, String zip, String entry, Map<String,String> map){
              try (FileSystem fileSystem = FileSystems.newFileSystem(URI.create("jar:file:"+ path + "/" + zip), map)) {
                 Path fileToExtract = fileSystem.getPath(entry);
                 Path fileOutZip = Paths.get(path + "/unzipped_" + entry );
                 Files.copy(fileToExtract, fileOutZip);
      
      }
      }
      

      【讨论】:

        【解决方案5】:

        我处理过一个案例:
        第 1 步:我在指定目录中有要解压缩的 zip 文件
        第 2 步:将解压缩文件(一个 zip 文件中的多个文件)存储在指定目录中)(注意:清理要移动解压缩文件的目标目录)。

        这是对我有用的代码:

        public String unZip(String zipFilePath, String destDirectory, String afilename) {
                
                String efilename; String[] files; String unzipfilePath; String[] oldFiles;
                File destDir = new File(destDirectory);
                if (destDir.isDirectory()) {
                    oldFiles = destDir.list();
                       for (int k = 0; k < oldFiles.length; k++) {
                           File oFiles = new File(oldFiles[k]);
                           logMessage("Old file name in the unziped folder is "+oFiles );
                           oFiles.delete();
                        }
                        
                    }
                if (!destDir.exists()) {
                    destDir.mkdir();
                }
                
                 ZipInputStream zipIn;
                try {
                    zipIn = new ZipInputStream(new FileInputStream(zipFilePath));
        
                    ZipEntry entry = zipIn.getNextEntry();
                    // iterates over entries in the zip file
                    while (entry != null) {
                        
                        unzipfilePath = destDirectory + File.separator + entry.getName();
                         
                        if (!entry.isDirectory()) {
                            // if the entry is a file, extracts it
                            extractFile(zipIn, unzipfilePath);
                             logMessage(" File copied to Unziped folder is " +unzipfilePath);
                        } else {
                            // if the entry is a directory, make the directory
                            File dir = new File(unzipfilePath);
                            dir.mkdir();
                        }
                        zipIn.closeEntry();
                        entry = zipIn.getNextEntry();
                    }
                    zipIn.close(); 
                    
                    // check for filename in the unzipped folder
                    
                    File dest = new File(destDirectory);
                    files = dest.list();
                    int flag = 0;
                    if (files == null) {
                        logMessage("Empty directory.");
                    }
                    else {
              
                        // Linear search in the array forf expected file name 
                        for (int i = 0; i < files.length; i++) {
                            efilename = files[i];
                            if (efilename.equals(afilename))
                                logMessage(efilename + " Expected File found in Unziped files folder");
                                flag = 1;
                                Assert.assertNotNull(efilename);
                               
                        }
                            
                    }
                    
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
                return efilename;
            }
        

        【讨论】: