package com.cn; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; //错误小结: //1 关于file.isFile()与file.isDirectory()记忆出了偏差. // 错误以为若是Directory一定是file,file不一定是Directory // 更正:file和Directory是两码事.只能是file或Directory中其中一个. // 要看的1 传入一个路径直接压缩了. //2 并不是说我们执行一句File f=new File("F:\\x.txt"); // 在本地硬盘上就生成了一个x.txt文件.而应该进行如下的 // 操作才可以. // File f=new File("F:\\x.txt"); // if (!f.exists()) { // f.createNewFile(); // } // 其中f.createNewFile()表示创建了一个空文件 // // 多数的情况下,我们执行了File f=new File("F:\\x.txt") // 以后再利用输入流,输出流对f进行操作,比如往该x.txt文件中 // 写入hello world // //3 血的教训: // zip()方法中没有关闭流zos.导致压缩后的文件解压时出错 //重要总结: //1 关于zip和unzip的核心操作对象是每一个文件!!! // 比如碰到一个directory,那么会去遍历里面的每一个文件,挨个对其进行压缩. // 不要错误地理解,若是一个directory,那么会将其作为一个整体进行压缩. //2 在JAVA中每一个压缩文件都用一个ZipEntry表示 // 所以在压缩的过程中要得到每个文件的完整路径(从最外层文件夹至文件本身) // 用此完整路径为每个压缩文件new()一个ZipEntry //3 所以利用zipEntry可记录原来的目录层次.解压后才保持原样 // 也可以看到在解压时利用entrys.hasMoreElements()来挨个 // 解压每个zipEntry. // 参见解压中的代码: // new File(unzipPath+File.separator+entry.getName()); public class TestZipAndUnZip { public static void main(String[] args) throws Exception { TestZipAndUnZip test=new TestZipAndUnZip(); //将某一个文件压缩成zip // test.zip("E:\\", "aa\\1.txt", "E:\\cc1.zip"); //将某一个目录压缩成zip //test.zip("E:\\aa", "bb\\", "E:\\zz.zip");//right // test.zip("F:\\", "kk", "F:\\zz678910.zip");//right // //// //将某一个zip解压 // test.unZipFile("F:\\zz678910.zip", "E:\\zzzz"); /////////////////////以下正确/////////////////////////////// //压缩和解压单个文件 test.zip2("F:\\kk\\cc.txt","F:\\88.zip"); test.unZipFile2("F:\\88.zip", "F:\\abc"); //压缩和解压一个目录 test.zip2("F:\\kk","F:\\9zip.zip"); test.unZipFile2("F:\\9zip.zip", "F:\\9files"); /////////////////////以上正确////////////////////////////// } /** * @param willZipDirPath 被压缩文件(目录)所在目录 * @param willZipFileName 被压缩文件(目录)的名称 * @param toFilePath 压缩后文件(目录)名 */ public void zip(String willZipDirPath, String willZipFileName, String zipedFileName) { System.out.println("…………………以下为zip()方法…………………………"); if (willZipDirPath == null) { return; } File willZipDir = new File(willZipDirPath); if (!willZipDir.exists() || !willZipDir.isDirectory()) { return; } // 获得目录绝对路径 String willZipDirAbsolutePath = willZipDir.getAbsolutePath(); System.out.println("willZipDir.getAbsolutePath()="+willZipDirAbsolutePath); //压缩后的文件 File zipedFile = new File(zipedFileName); try { //从压缩后的文件得到压缩输出流ZipOutputStream //这里的zos只指向了压缩后文件的最外层.那么它怎么 //维持了原来的目录结构呢? //就是利用了ZipEntry!!! //在fileToZip()方法中就可以看到ZipEntry的使用!! ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipedFile)); if (willZipFileName.equals("*")) { //若传入的是*表示将此路径下所有东西都要压缩 //所以调用dirToZip() dirToZip(willZipDirAbsolutePath, willZipDir, zos); } else { //将被压缩的文件 File willZipFile = new File(willZipDirPath, willZipFileName); System.out.println("ccccccccccc name="+willZipFile.getName()); System.out.println("ccccccccccc getAbsolutePath="+willZipFile.getAbsolutePath()); if (willZipFile.isFile()) { System.out.println("…………………最外层开始压缩文件………………………"); fileToZip(willZipDirPath, willZipFile, zos); System.out.println("…………………最外层压缩文件结束………………………"); } if (willZipFile.isDirectory()) { System.out.println("…………………最外层开始压缩目录………………………"); dirToZip(willZipDirPath, willZipFile, zos); System.out.println("…………………最外层压缩目录结束………………………"); } // 关闭流!!! zos.close(); System.out.println("…………………以上为zip()方法…………………………"); } } catch (Exception e) { // TODO: handle exception } } /** * @param dirPath 被压缩文件所在目录 * @param willZipFile 被压缩文件的名称 * @param zos 输出流 */ public void fileToZip(String dirPath, File willZipFile,ZipOutputStream zos){ FileInputStream fis=null; ZipEntry zipEntry=null; byte [] buffer=new byte[1024*8]; int len=0; if (willZipFile.isFile()) { try { fis=new FileInputStream(willZipFile); zipEntry=new ZipEntry(getEntryName(dirPath, willZipFile)); zos.putNextEntry(zipEntry); System.out.println("…………………以下为fileToZip()方法…………………………"); System.out.println("zipEntry.getName="+zipEntry.getName()); System.out.println("zipEntry.isDirectory="+zipEntry.isDirectory()); System.out.println("zipEntry.getSize="+zipEntry.getSize()); System.out.println("zipEntry.getTime="+zipEntry.getTime()); System.out.println("zipEntry.getComment="+zipEntry.getComment()); System.out.println("…………………以上为fileToZip()方法…………………………"); while((len=fis.read(buffer))!=-1){ zos.write(buffer, 0, len); } zos.closeEntry(); fis.close(); } catch (Exception e) { } } } /** * @param dirPath 被压缩目录所在的上级目录 * @param willZipDir 被压缩目录 * @param zos 输出流 */ public void dirToZip(String dirPath, File willZipDir, ZipOutputStream zos) { if (willZipDir.isDirectory()) { File[] files = willZipDir.listFiles(); //处理-->该文件夹下无文件 if (files.length==0) { ZipEntry zipEntry=new ZipEntry(getEntryName(dirPath, willZipDir)); System.out.println("xxxxxxxxxxxxxxxx "+zipEntry.getName()); try { zos.putNextEntry(zipEntry); //zos.closeEntry(); } catch (Exception e) { e.printStackTrace(); } return; } //处理-->该文件夹下的所有文件 for (int i = 0; i < files.length; i++) { File file = files[i]; //若是文件,递归调用fileToZip() if (file.isFile()) { System.out.println("xxxxxxxxxx内层开始fileToZip()方法xxxxxxxxxx"); fileToZip(dirPath, file, zos); System.out.println("xxxxxxxxxx内层fileToZip()方法结束xxxxxxxxxx"); } //若是文件,递归调用dirToZip() if (file.isDirectory()) { System.out.println("xxxxxxxxxx内层开始dirToZip()方法xxxxxxxxxx"); dirToZip(dirPath, file, zos); System.out.println("xxxxxxxxxx内层dirToZip()方法结束xxxxxxxxxx"); } } } } /** * @param dirPath 将被压缩文件所在目录 * @param willZipFile 将被压缩的文件 * @return */ //生成的是每个文件的完整路径(从最外层文件夹至文件本身) //这样生成的zipEntry就记录了原来的目录层次.解压后才保持原样 public String getEntryName(String dirPath, File willZipFile) { if (!dirPath.endsWith(File.separator)) { dirPath += File.separator; } String willZipFilePath=willZipFile.getAbsolutePath(); if (willZipFile.isDirectory()) { willZipFilePath+="/"; } int index=willZipFilePath.indexOf(dirPath); System.out.println("xx返回的 entryName="+ willZipFilePath.substring(index+dirPath.length())); return willZipFilePath.substring(index+dirPath.length()); } /** * @param zipedFileName 待解压zip文件 * @param unzipDirPath 文件解压后的最外层文件名 * @throws IOException */ public void unZipFile(String zipedFileName,String unzipDirPath) throws Exception{ if (!unzipDirPath.endsWith(File.separator)) { unzipDirPath+=File.separator; } try { ZipFile zipedFile=new ZipFile(zipedFileName); ZipEntry zipEntry=null; String entryName=null; String unzipedFileName=null; Enumeration entrys=zipedFile.entries(); byte [] buffer=new byte[1024*8]; int len=0; while (entrys.hasMoreElements()) { zipEntry=(ZipEntry) entrys.nextElement(); entryName=zipEntry.getName(); unzipedFileName=unzipDirPath+entryName; System.out.println("…………………以下为unZipFile()方法…………………………"); System.out.println("zipedFileName="+zipedFileName); System.out.println("unzipDirPath="+unzipDirPath); System.out.println("entryName="+entryName); System.out.println("unzipedFileName="+unzipedFileName); System.out.println("…………………以上为unZipFile()方法…………………………"); if (zipEntry.isDirectory()) { //没有执行此代码 System.out.println("999999999999"); new File(unzipedFileName).mkdirs(); } else { //总是执行该代码.因为压缩的时候是对每个文件进行压缩的. new File(unzipedFileName).getParentFile().mkdirs(); } FileOutputStream fos=null; InputStream is=null; File unzipedFile=new File(unzipedFileName); if (unzipedFile.isDirectory()) { File [] files=unzipedFile.listFiles(); for (int i = 0; i < files.length; i++) { File file = files[i]; fos=new FileOutputStream(file); is=zipedFile.getInputStream(zipEntry); while ((len=is.read(buffer))!=-1) { fos.write(buffer, 0, len); } } }else{ fos=new FileOutputStream(unzipedFile); is=zipedFile.getInputStream(zipEntry); while ((len=is.read(buffer))!=-1) { fos.write(buffer, 0, len); } } //这里需要修改 //fos.close(); //is.close(); } } catch (Exception e) { e.printStackTrace(); } } ///////////////////////////////////////////////////////////////////////////////////// /** * 该方法将一个给定路径的文件压缩 * @param willZipPath 待压缩文件的路径 * @param zipedPath 该文件压缩后的路径 */ public void zip2(String willZipPath, String zipedPath) { try { File willZipFile = new File(willZipPath); File zipedFile = new File(zipedPath); ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipedFile)); if (willZipFile.isFile()) { fileToZip2(willZipPath, zos); } if (willZipFile.isDirectory()) { dirToZip2(willZipPath, willZipFile, zos); } // 方法调用完成后关闭流 zos.close(); } catch (Exception e) { // TODO: handle exception } } /** * @param willZipFilePath 待压缩文件的路径 * @param zos 压缩文件输出流 * 1 关于以下两句代码 * ZipEntry entry = new ZipEntry(); * zos.putNextEntry(entry); * 把生成的ZipEntry对象加入到压缩文件中 * 之后往压缩文件中写入的内容均放在该ZipEntry对象中 * * 2 fis.close()但是不能在此处zos.close() * 因为该zos是上一方法传递过来的.可能在压缩目录的时候会 * 再次使用到该zos流.若此时关闭,则导致目录中的一个文件 * 被压缩 */ public void fileToZip2(String willZipFilePath,ZipOutputStream zos){ try { File willZipFile=new File(willZipFilePath); ZipEntry entry = new ZipEntry(getEntryName2(willZipFilePath, willZipFile)); zos.putNextEntry(entry); FileInputStream fis = new FileInputStream(willZipFilePath); int len = 0; while ((len = fis.read()) != -1){ zos.write(len); } fis.close(); //流关闭错误! //zos.close(); } catch (Exception e) { } } /** * @param willZipDirctoryPath 原目录所在路径 * @param willZipedDirectory 原目录 * @param zos 压缩流 * 注意: * 在处理空文件夹的时候 * getEntryName2(willZipDirctoryPath, willZipedDirectory)+"/" * 中的"/"是比不可少的 */ public void dirToZip2(String willZipDirctoryPath,File willZipedDirectory, ZipOutputStream zos) { if (willZipedDirectory.isDirectory()) { File[] files = willZipedDirectory.listFiles(); //处理空文件夹的情况 if (files.length==0) { ZipEntry zipEntry=new ZipEntry (getEntryName2(willZipDirctoryPath, willZipedDirectory)+"/"); try { zos.putNextEntry(zipEntry); } catch (Exception e) { e.printStackTrace(); } return; } for (int i = 0; i < files.length; i++) { File file = files[i]; //若是文件,递归调用fileToZip() if (file.isFile()) { fileToZip2(file.getAbsolutePath(), zos); } //若是文件,递归调用dirToZip() if (file.isDirectory()) { dirToZip2(file.getAbsolutePath(),file, zos); } } } } /** * @param rawPath 需要压缩的目录或者文件的完整路径 * @param file 需要压缩的文件或者目录 * @return entryName * * 该方法返回EntryName,表示从最外层目录开始到该文件(目录) * 的完整路径 * 备注: * 1 该示例中文件均存放在某盘下,如E:\所以rawPath.substring(3); * 2 注释中"@param file 需要压缩的文件或者目录".其实绝大多数情况下 * 都是文件,只有一种情况是目录,就是空文件夹的情况. */ public String getEntryName2(String rawPath,File file){ try { String rawDir=rawPath.substring(3); int rawDirIndex=file.getAbsolutePath().indexOf(rawDir); String entryName=file.getAbsolutePath().substring(rawDirIndex); return entryName; } catch (Exception e) { } return null; } /** * @param zipedFilePath 原压缩文件的路径 * @param unzipPath 文件解压后的路径 * 对于文件或者目录操作的小梳理: * 1 对于目录应该先执行file.mkdir(s)()才可以 * 往里面其下存入文件.比如: * File f=new File("F:\\test\\x.txt"); if (!f.exists()) { f.createNewFile(); } 这当然要报错,因为x.txt的所在目录还不存在!! 所以应该改正为: File f=new File("F:\\test\\x.txt"); f.getParentFile().mkdirs(); if (!f.exists()) { f.createNewFile(); } 2同样的道理 File f=new File("F:\\test\\x.txt"); if (f.isFile()) { System.out.println("true"); }else{ System.out.println("false"); } 结果为false 3类似的问题 File f=new File("F:\\x.txt"); if (f.isFile()) { System.out.println("true"); }else{ System.out.println("false"); } 结果为false 因为只是new了一个File,并没有创建!!! File f=new File("F:\\x.txt"); f.createNewFile(); if (f.isFile()) { System.out.println("true"); }else{ System.out.println("false"); } 此时为true 此处: if (zipEntry.isDirectory()) { new File(perUnzipFilePath).mkdirs(); } else { new File(perUnzipFilePath).getParentFile().mkdirs(); } 已经建立了每个文件夹. 然后才开始对每个空文件夹和每个文件进行流操作. 和上面的道理一致,刚开始犯了个错误,没有采用 else { fos = new FileOutputStream(perUnzipFile); is = zipFile.getInputStream(zipEntry); while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } } 而是用if(perUnzipFile.isFile()){}来操作,这当然错了. 因为该perUnzipFile没有执行perUnzipFile.createNewFile(); 所以它还不是File.类似的情况,多采用流操作来进行读写. 所以总结两种与File有关的操作: 1 File f=new File(""); f.createNewFile(); 然后对f操作 2 file f=new File(""); 然后用输入输出流进行流操作 举例子: File f=new File("F:\\2221x.txt"); FileOutputStream fos=new FileOutputStream(f); String string="hello"; byte []b=string.getBytes(); fos.write(b, 0, b.length); 该例子是正确的. 疑问:没有执行 f.createNewFile()为什么不报错.因为输出流 FileOutputStream已经帮我们做了该工作了. 修改例子即可知: File f=new File("F:\\2221x.txt"); if (f.isFile()) { System.out.println("true1"); } else { System.out.println("false1"); } FileOutputStream fos=new FileOutputStream(f); if (f.isFile()) { System.out.println("true2"); } else { System.out.println("false2"); } String string="hello"; byte []b=string.getBytes(); fos.write(b, 0, b.length); 输出false1,true2 这就得到了验证. */ public void unZipFile2(String zipedFilePath, String unzipPath) { FileOutputStream fos=null; InputStream is=null; ZipEntry zipEntry=null; String perUnzipFilePath=null; if (!unzipPath.endsWith(File.separator)) { unzipPath+=File.separator; } try { ZipFile zipFile=new ZipFile(zipedFilePath); Enumeration entries=zipFile.entries(); byte [] buffer=new byte[1024*8]; int len=0; while (entries.hasMoreElements()) { zipEntry = (ZipEntry) entries.nextElement(); perUnzipFilePath = unzipPath + zipEntry.getName(); //1建立每个文件夹 if (zipEntry.isDirectory()) { //处理空文件夹的情况 //创建空目录 new File(perUnzipFilePath).mkdirs(); } else { //为每个文件创立其所在目录 new File(perUnzipFilePath).getParentFile().mkdirs(); } //2在用流操作处理每个文件夹中的文件 // 2.1if中的操作只是针对空目录而进行的.所以if中的代码可以 // 注释掉,无实际意义. // 2.2else中的操作是对于每个具体的文件而进行的流操作 File perUnzipFile = new File(perUnzipFilePath); if (perUnzipFile.isDirectory()) { File[] files = perUnzipFile.listFiles(); for (int i = 0; i < files.length; i++) { File file = files[i]; fos = new FileOutputStream(file); is = zipFile.getInputStream(zipEntry); while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } } } else { fos = new FileOutputStream(perUnzipFile); is = zipFile.getInputStream(zipEntry); while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } } } if (fos!=null) { fos.close(); } if (is!=null) { is.close(); } } catch (Exception e) { e.printStackTrace(); } } }
时间: 2024-10-29 00:48:21