diff --git a/javase-tutorials/pom.xml b/javase-tutorials/pom.xml index 0738465..4fb3bab 100644 --- a/javase-tutorials/pom.xml +++ b/javase-tutorials/pom.xml @@ -26,7 +26,7 @@ ${project.basedir}/src/main/webapp/WEB-INF/lib/xxx.jar --> - + @@ -44,8 +44,8 @@ qrgen 1.3 - - + + net.coobird @@ -53,7 +53,30 @@ 0.4.7 + + + joda-time + joda-time + 2.4 + + + + + net.lingala.zip4j + zip4j + 1.3.2 + + + org.apache.commons + commons-lang3 + 3.3.2 + + + junit + junit + 4.11 + diff --git a/javase-tutorials/src/main/java/org/javase/tutorials/BinarySearch.java b/javase-tutorials/src/main/java/org/javase/tutorials/BinarySearch.java index 9e1ca78..b1d0a78 100644 --- a/javase-tutorials/src/main/java/org/javase/tutorials/BinarySearch.java +++ b/javase-tutorials/src/main/java/org/javase/tutorials/BinarySearch.java @@ -3,7 +3,7 @@ package org.javase.tutorials; /** * 二分法查找 - * @author welcome + * @author 冯靖 * */ public class BinarySearch { diff --git a/javase-tutorials/src/main/java/org/javase/tutorials/SwapVar.java b/javase-tutorials/src/main/java/org/javase/tutorials/SwapVar.java index 4e84208..2ff394f 100644 --- a/javase-tutorials/src/main/java/org/javase/tutorials/SwapVar.java +++ b/javase-tutorials/src/main/java/org/javase/tutorials/SwapVar.java @@ -2,7 +2,7 @@ package org.javase.tutorials; /** * 交换两个数的值,不借助于第三个数 - * @author welcome + * @author 冯靖 * */ public class SwapVar { diff --git a/javase-tutorials/src/main/java/org/javase/tutorials/jodatime/Jodatime.java b/javase-tutorials/src/main/java/org/javase/tutorials/jodatime/Jodatime.java new file mode 100644 index 0000000..e102349 --- /dev/null +++ b/javase-tutorials/src/main/java/org/javase/tutorials/jodatime/Jodatime.java @@ -0,0 +1,292 @@ +package org.javase.tutorials.jodatime; + +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +import org.joda.time.DateTime; +import org.joda.time.DateTimeConstants; +import org.joda.time.DateTimeZone; +import org.joda.time.Duration; +import org.joda.time.Interval; +import org.joda.time.LocalDate; +import org.joda.time.LocalTime; +import org.joda.time.Period; +import org.joda.time.PeriodType; + +/** + * joda-time + * @author 冯靖 + * + */ +public class Jodatime { + + /** + * @param args + */ + public static void main(String[] args) { + getTime(); + getTimeInfo(); + convertJDK(); + date(); + } + + private static void getTime(){ + + //方法一:取系统点间 + DateTime dt1 = new DateTime(); + + print("方法一:取系统点间",dt1); + + //方法二:通过java.util.Date对象生成 + DateTime dt2 = new DateTime(new Date()); + + print("方法二:通过java.util.Date对象生成",dt2); + + //方法三:指定年月日点分秒生成(参数依次是:年,月,日,时,分,秒,毫秒) + DateTime dt3 = new DateTime(2012, 5, 20, 13, 14, 0, 0); + + print("方法三:指定年月日点分秒生成(参数依次是:年,月,日,时,分,秒,毫秒)",dt3); + + //方法四:ISO8601形式生成 + DateTime dt4 = new DateTime("2012-05-20"); + + print("方法四:ISO8601形式生成",dt4); + + DateTime dt5 = new DateTime("2012-05-20T13:14:00"); + + print("方法四:ISO8601形式生成",dt5); + + //只需要年月日的时候 + LocalDate localDate = new LocalDate(2009, 9, 6);// September 6, 2009 + + System.out.println(localDate.toString("YYYY-MM-dd")); + + //只需要时分秒毫秒的时候 + LocalTime localTime = new LocalTime(13, 30, 26, 0);// 1:30:26PM + + System.out.println(localTime.toString("hh:mm:ss.SSSa")); + } + + + private static void getTimeInfo(){ + + System.out.println("-------------获取当前时间-----------------"); + + String weekStr=""; + + DateTime dt = new DateTime(); + //年 + int year = dt.getYear(); + //月 + int month = dt.getMonthOfYear(); + //日 + int day = dt.getDayOfMonth(); + //星期 + int week = dt.getDayOfWeek(); + //点 + int hour = dt.getHourOfDay(); + //分 + int min = dt.getMinuteOfHour(); + //秒 + int sec = dt.getSecondOfMinute(); + //毫秒 + int msec = dt.getMillisOfSecond(); + + //星期 + switch(week) { + case DateTimeConstants.SUNDAY: + weekStr = "星期日"; + System.out.println(weekStr); + break; + case DateTimeConstants.MONDAY: + weekStr = "星期一"; + System.out.println(weekStr); + break; + case DateTimeConstants.TUESDAY: + weekStr = "星期二"; + System.out.println(weekStr); + break; + case DateTimeConstants.WEDNESDAY: + weekStr = "星期三"; + System.out.println(weekStr); + break; + case DateTimeConstants.THURSDAY: + weekStr = "星期四"; + System.out.println(weekStr); + break; + case DateTimeConstants.FRIDAY: + weekStr = "星期五"; + System.out.println(weekStr); + break; + case DateTimeConstants.SATURDAY: + weekStr = "星期六"; + System.out.println(weekStr); + break; + } + + System.out.println(year + "/" + month + "/" + day + " " + hour + ":" + min + ":" + sec + ":" + msec + " " + weekStr); + + } + + /** + * 与jdk的时间转换 + */ + public static void convertJDK(){ + + System.out.println("-------------与jdk的时间转换-----------------"); + + DateTime dt = new DateTime(); + + //转换成java.util.Date对象 + + Date d1 = new Date(dt.getMillis()); + + Date d2 = dt.toDate(); + + //转换成java.util.Calendar对象 + Calendar c1 = Calendar.getInstance(); + c1.setTimeInMillis(dt.getMillis()); + + Calendar c2 = dt.toCalendar(Locale.getDefault()); + + } + + /** + * 日期推算 + */ + public static void date(){ + + System.out.println("-------------日期推算-----------------"); + + DateTime dt = new DateTime(); + + print("今天",dt); + + //昨天 + DateTime yesterday = dt.minusDays(1); + + print("昨天",yesterday); + + //明天 + DateTime tomorrow = dt.plusDays(1); + + print("明天",tomorrow); + + //1个月前 + DateTime before1month = dt.minusMonths(1); + + print("1个月前",before1month); + + //3个月后 + DateTime after3month = dt.plusMonths(3); + + print("3个月后",after3month); + + //2年前 + DateTime before2year = dt.minusYears(2); + + print("2年前",before2year); + + //5年后 + DateTime after5year = dt.plusYears(5); + + print("5年后",after5year); + + //特殊日期处理 + + //月末日期 + DateTime lastday = dt.dayOfMonth().withMaximumValue(); + + print("月末日期",lastday); + + //90天后那周的周一 + DateTime firstday = dt.plusDays(90).dayOfWeek().withMinimumValue(); + + print("90天后那周的周一",firstday); + + //时区 + System.out.println("-------------时区-----------------"); + //默认设置为日本时间 + DateTimeZone.setDefault(DateTimeZone.forID("Asia/Tokyo")); + + DateTime dt1 = new DateTime(); + + print("默认设置为日本时间",dt1); + + //伦敦时间 + DateTime dt2 = new DateTime(DateTimeZone.forID("Europe/London")); + + print("伦敦时间",dt2); + + //计算区间 + + System.out.println("-------------计算区间-----------------"); + + DateTime begin = new DateTime("2012-02-01"); + + DateTime end = new DateTime("2012-05-01"); + + //计算区间毫秒数 + Duration d = new Duration(begin, end); + long time = d.getMillis(); + + System.out.println("计算区间毫秒数:"+time); + + //计算区间天数 + Period p = new Period(begin, end, PeriodType.days()); + int days = p.getDays(); + + System.out.println("计算区间天数:"+days); + + //计算特定日期是否在该区间内 + Interval i = new Interval(begin, end); + boolean contained = i.contains(new DateTime("2012-03-01")); + + + //日期比较 + System.out.println("-------------日期比较-----------------"); + + DateTime d1 = new DateTime("2012-02-01"); + DateTime d2 = new DateTime("2012-05-01"); + + //和系统时间比 + boolean b1 = d1.isAfterNow();//将来 以后 + System.out.println("["+b1+"]"+d1.toString("yyyy-MM-dd")+"在"+dt.toString("yyyy-MM-dd")+"之前"); + boolean b2 = d1.isBeforeNow();//以前 过去 + System.out.println("["+b2+"]"+d1.toString("yyyy-MM-dd")+"在"+dt.toString("yyyy-MM-dd")+"之前"); + boolean b3 = d1.isEqualNow();//与现在时间相同 + System.out.println("["+b3+"]"+d1.toString("yyyy-MM-dd")+"与"+dt.toString("yyyy-MM-dd")+"相同"); + + + //和其他日期比 + boolean f1 = d1.isAfter(d2); + boolean f2 = d1.isBefore(d2); + boolean f3 = d1.isEqual(d2); + + + //格式化输出 + + System.out.println("-------------格式化输出-----------------"); + + DateTime dateTime = new DateTime(); + + String s1 = dateTime.toString("yyyy/MM/dd hh:mm:ss.SSSa"); + String s2 = dateTime.toString("yyyy-MM-dd HH:mm:ss"); + String s3 = dateTime.toString("EEEE dd MMMM, yyyy HH:mm:ssa"); + String s4 = dateTime.toString("yyyy/MM/dd HH:mm ZZZZ"); + String s5 = dateTime.toString("yyyy/MM/dd HH:mm Z"); + + System.out.println(s1); + System.out.println(s2); + System.out.println(s3); + System.out.println(s4); + System.out.println(s5); + } + + + private static void print(String tag,DateTime dateTime){ + System.out.println(tag + ":" + dateTime.toString("yyyy-MM-dd HH:mm:ss")); + } + +} diff --git a/javase-tutorials/src/main/java/org/javase/tutorials/qrcode/QRcode.java b/javase-tutorials/src/main/java/org/javase/tutorials/qrcode/QRcode.java index 8223c4b..9f38e96 100644 --- a/javase-tutorials/src/main/java/org/javase/tutorials/qrcode/QRcode.java +++ b/javase-tutorials/src/main/java/org/javase/tutorials/qrcode/QRcode.java @@ -1,10 +1,22 @@ package org.javase.tutorials.qrcode; +import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.io.OutputStream; +import javax.imageio.ImageIO; + +import com.google.zxing.BinaryBitmap; +import com.google.zxing.LuminanceSource; +import com.google.zxing.Result; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.QRCodeReader; + import net.glxn.qrgen.QRCode; import net.glxn.qrgen.image.ImageType; @@ -12,7 +24,7 @@ import net.glxn.qrgen.image.ImageType; /** * 使用qrgen生成二维码 * - * @author welcome + * @author 冯靖 * */ public class QRcode { @@ -22,9 +34,54 @@ public class QRcode { */ public static void main(String[] args) throws Exception{ - ByteArrayOutputStream out = QRCode.from("雪山飞鹄").withCharset("utf-8").withSize(480, 320).to(ImageType.PNG).stream(); + File file = new File("target","qrcode.png"); + + String content = "http://aimeizi.net"; + + String charset = "utf-8"; + + int width = 320; + + int height = 320; + + generateCode(content,charset,width,height,file); + + readCode(file); + + } + + + + /** + * 读取二维码 + * @param file 二维码源 + * @throws Exception + */ + private static void readCode(File file) throws Exception{ + BufferedImage encodedBufferedImage = ImageIO.read(file) ; + LuminanceSource source = new BufferedImageLuminanceSource(encodedBufferedImage); + Result result = new QRCodeReader().decode(new BinaryBitmap(new HybridBinarizer(source))); + System.out.println(result.getText()); + } - OutputStream outStream = new FileOutputStream(new File("target","qrcode.png")); + + + + /** + * 生成二维码 + * @param content 内容 + * @param charset 字符编码 + * @param width 宽 + * @param height 高 + * @param target 生成后写入路径 + * @throws FileNotFoundException + * @throws IOException + */ + private static void generateCode(String content,String charset,int width,int height,File target) throws FileNotFoundException,IOException { + + ByteArrayOutputStream out = QRCode.from(content).withCharset(charset).withSize(width, height).to(ImageType.PNG).stream(); + + OutputStream outStream = new FileOutputStream(target); outStream.write(out.toByteArray()); diff --git a/javase-tutorials/src/main/java/org/javase/tutorials/sort/Sort.java b/javase-tutorials/src/main/java/org/javase/tutorials/sort/Sort.java index bbbcc48..859e4c1 100644 --- a/javase-tutorials/src/main/java/org/javase/tutorials/sort/Sort.java +++ b/javase-tutorials/src/main/java/org/javase/tutorials/sort/Sort.java @@ -4,6 +4,8 @@ import java.util.Arrays; /** * 排序算法接口 + * @author 冯靖 + * */ public interface Sort { diff --git a/javase-tutorials/src/main/java/org/javase/tutorials/sort/SortTest.java b/javase-tutorials/src/main/java/org/javase/tutorials/sort/SortTest.java index 2ab89b6..e60b019 100644 --- a/javase-tutorials/src/main/java/org/javase/tutorials/sort/SortTest.java +++ b/javase-tutorials/src/main/java/org/javase/tutorials/sort/SortTest.java @@ -6,7 +6,9 @@ import org.javase.tutorials.sort.Sort.SortUtil; import org.javase.tutorials.sort.Sort.Sorts; /** - * 冒择入希快归堆:常用排序算法 + * 常用排序算法 + * @author 冯靖 + * */ public class SortTest { diff --git a/javase-tutorials/src/main/java/org/javase/tutorials/thumbnailator/Thumbnailator.java b/javase-tutorials/src/main/java/org/javase/tutorials/thumbnailator/Thumbnailator.java index cfd62a9..861eb00 100644 --- a/javase-tutorials/src/main/java/org/javase/tutorials/thumbnailator/Thumbnailator.java +++ b/javase-tutorials/src/main/java/org/javase/tutorials/thumbnailator/Thumbnailator.java @@ -1,17 +1,227 @@ package org.javase.tutorials.thumbnailator; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; + +import javax.imageio.ImageIO; + +import net.coobird.thumbnailator.Thumbnails; +import net.coobird.thumbnailator.geometry.Positions; + +import org.junit.Test; + /** * Java缩略图生成类库 + * @see https://code.google.com/p/thumbnailator/wiki/Examples + * @author 冯靖 + * + */ +/** * @author welcome * */ public class Thumbnailator { - /** - * @param args - */ - public static void main(String[] args) { - - } + /** + * 指定大小进行缩放 + */ + @Test + public void example1() throws Exception{ + //size(宽度, 高度) + /* + * 若图片横比200小,高比300小,不变 + * 若图片横比200小,高比300大,高缩小到300,图片比例不变 + * 若图片横比200大,高比300小,横缩小到200,图片比例不变 + * 若图片横比200大,高比300大,图片按比例缩小,横为200或高为300 + */ + Thumbnails.of("src/main/resources/example.jpg").size(200, 300).toFile("src/main/resources/200x300.jpg"); + Thumbnails.of("src/main/resources/example.jpg").size(2560, 2048).toFile("src/main/resources/2560x2048.jpg"); + + } + + + /** + * 按照比例进行缩放 + */ + @Test + public void example2() throws Exception{ + //scale(比例) + Thumbnails.of("src/main/resources/example.jpg") + .scale(0.25f) + //.outputQuality(0.8) + .toFile("src/main/resources/25%.jpg"); + + Thumbnails.of("src/main/resources/example.jpg") + .scale(1.10f) + //.outputQuality(0.8) + .toFile("src/main/resources/110%.jpg"); + + } + + + /** + * 不按照比例,指定大小进行缩放 + */ + @Test + public void example3() throws Exception{ + //keepAspectRatio(false) 默认是按照比例缩放的 + Thumbnails.of("src/main/resources/example.jpg") + .size(200, 200) + .keepAspectRatio(false) + .toFile("src/main/resources/200x200.jpg"); + } + + + /** + * 旋转 + */ + @Test + public void example4() throws Exception{ + //rotate(角度),正数:顺时针 负数:逆时针 + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .rotate(90) + .toFile("src/main/resources/rotate+90.jpg"); + + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .rotate(-90) + .toFile("src/main/resources/rotate-90.jpg"); + + } + + + /** + * 水印 + */ + @Test + public void example5() throws Exception{ + //watermark(位置,水印图,透明度) + + //左上角 + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .watermark(Positions.TOP_LEFT, ImageIO.read(new File("src/main/resources/watermark.png")), 0.5f) + .outputQuality(0.8f) + .toFile("src/main/resources/a380_watermark_top_left.jpg"); + + //左下角 + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .watermark(Positions.BOTTOM_LEFT, ImageIO.read(new File("src/main/resources/watermark.png")), 0.5f) + .outputQuality(0.8f) + .toFile("src/main/resources/a380_watermark_bottom_left.jpg"); + + + //右上角 + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .watermark(Positions.TOP_RIGHT, ImageIO.read(new File("src/main/resources/watermark.png")), 0.5f) + .outputQuality(0.8f) + .toFile("src/main/resources/a380_watermark_top_right.jpg"); + + + //右下角 + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File("src/main/resources/watermark.png")), 0.5f) + .outputQuality(0.8f) + .toFile("src/main/resources/a380_watermark_bottom_right.jpg"); + + //局中 + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .watermark(Positions.CENTER, ImageIO.read(new File("src/main/resources/watermark.png")), 0.5f) + .outputQuality(0.8f) + .toFile("src/main/resources/a380_watermark_center.jpg"); + + } + + + /** + * 裁剪 + */ + @Test + public void example6() throws Exception{ + //sourceRegion() + //图片中心400*400的区域 + Thumbnails.of("src/main/resources/example.jpg") + .sourceRegion(Positions.CENTER, 400,400) + .size(200, 200) + .keepAspectRatio(false) + .toFile("src/main/resources/a380_region_center.jpg"); + + //图片右下400*400的区域 + Thumbnails.of("src/main/resources/example.jpg") + .sourceRegion(Positions.BOTTOM_RIGHT, 400,400) + .size(200, 200) + .keepAspectRatio(false) + .toFile("src/main/resources/a380_region_bootom_right.jpg"); + + //指定坐标 + Thumbnails.of("src/main/resources/example.jpg") + .sourceRegion(300, 250, 260, 260) + .size(200, 200) + .keepAspectRatio(false) + .toFile("src/main/resources/a380_region_coord.jpg"); + + } + + + /** + * 转化图像格式 + */ + @Test + public void example7() throws Exception{ + //outputFormat(图像格式) + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .outputFormat("png") + .toFile("src/main/resources/a380_1280x1024.png"); + + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .outputFormat("gif") + .toFile("src/main/resources/a380_1280x1024.gif"); + } + + + + /** + * 输出到OutputStream + */ + @Test + public void example8() throws Exception{ + //toOutputStream(流对象) + OutputStream os = new FileOutputStream("src/main/resources/a380_1280x1024_OutputStream.png"); + Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .toOutputStream(os); + + } + + + /** + * 输出到BufferedImage + */ + @Test + public void example9() throws Exception{ + //asBufferedImage() 返回BufferedImage + BufferedImage thumbnail = Thumbnails.of("src/main/resources/example.jpg") + .size(1280, 1024) + .asBufferedImage(); + ImageIO.write(thumbnail, "jpg", new File("src/main/resources/a380_1280x1024_BufferedImage.jpg")); + + } + + + + + + + + } diff --git a/javase-tutorials/src/main/java/org/javase/tutorials/zip4j/CompressUtil.java b/javase-tutorials/src/main/java/org/javase/tutorials/zip4j/CompressUtil.java new file mode 100644 index 0000000..d201426 --- /dev/null +++ b/javase-tutorials/src/main/java/org/javase/tutorials/zip4j/CompressUtil.java @@ -0,0 +1,329 @@ +package org.javase.tutorials.zip4j; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +import net.lingala.zip4j.core.ZipFile; +import net.lingala.zip4j.exception.ZipException; +import net.lingala.zip4j.model.FileHeader; +import net.lingala.zip4j.model.ZipParameters; +import net.lingala.zip4j.util.Zip4jConstants; + +/** + * ZIP压缩文件操作工具类 支持密码,默认采用UTF-8编码 依赖zip4j开源项目(http://www.lingala.net/zip4j/) + * 版本1.3.2 + * + * @author ninemax + */ +public class CompressUtil { + + /** + * 使用给定密码解压指定的ZIP压缩文件到指定目录 + *

+ * 如果指定目录不存在,可以自动创建,不合法的路径将导致异常被抛出 + * + * @param zip + * 指定的ZIP压缩文件 + * @param dest + * 解压目录 + * @param passwd + * ZIP文件的密码 + * @return 解压后文件数组 + * @throws ZipException + * 压缩文件有损坏或者解压缩失败抛出 + */ + public static File[] unzip(String zip, String dest, String passwd) + throws ZipException { + File zipFile = new File(zip); + return unzip(zipFile, dest, passwd, null); + } + + /** + * 使用给定密码解压指定的ZIP压缩文件到当前目录 + * + * @param zip + * 指定的ZIP压缩文件 + * @param passwd + * ZIP文件的密码 + * @return 解压后文件数组 + * @throws ZipException + * 压缩文件有损坏或者解压缩失败抛出 + */ + public static File[] unzip(String zip, String passwd) throws ZipException { + File zipFile = new File(zip); + File parentDir = zipFile.getParentFile(); + return unzip(zipFile, parentDir.getAbsolutePath(), passwd, null); + } + + /** + * 使用给定密码解压指定的ZIP压缩文件到指定目录 + *

+ * 如果指定目录不存在,可以自动创建,不合法的路径将导致异常被抛出 + * + * @param zip + * 指定的ZIP压缩文件 + * @param dest + * 解压目录 + * @param passwd + * ZIP文件的密码 + * @param charset + * ZIP文件的编码 + * @return 解压后文件数组 + * @throws ZipException + * 压缩文件有损坏或者解压缩失败抛出 + */ + public static File[] unzip(File zipFile, String dest, String passwd, + String charset) throws ZipException { + ZipFile zFile = new ZipFile(zipFile); + if (null != charset || !"".equals(charset)) { + zFile.setFileNameCharset(charset); + } + if (!zFile.isValidZipFile()) { + throw new ZipException("压缩文件不合法,可能被损坏."); + } + File destDir = new File(dest); + if (destDir.isDirectory() && !destDir.exists()) { + destDir.mkdir(); + } + if (zFile.isEncrypted()) { + zFile.setPassword(passwd.toCharArray()); + } + zFile.extractAll(dest); + + List headerList = zFile.getFileHeaders(); + List extractedFileList = new ArrayList(); + for (FileHeader fileHeader : headerList) { + if (!fileHeader.isDirectory()) { + extractedFileList.add(new File(destDir, fileHeader + .getFileName())); + } + } + File[] extractedFiles = new File[extractedFileList.size()]; + extractedFileList.toArray(extractedFiles); + return extractedFiles; + } + + /** + * 压缩指定文件到当前文件夹 + * + * @param src + * 要压缩的指定文件 + * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. + */ + public static String zip(String src) { + return zip(src, null); + } + + /** + * 使用给定密码压缩指定文件或文件夹到当前目录 + * + * @param src + * 要压缩的文件 + * @param passwd + * 压缩使用的密码 + * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. + */ + public static String zip(String src, String passwd) { + return zip(src, null, passwd); + } + + /** + * 使用给定密码压缩指定文件或文件夹到当前目录 + * + * @param src + * 要压缩的文件 + * @param dest + * 压缩文件存放路径 + * @param passwd + * 压缩使用的密码 + * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. + */ + public static String zip(String src, String dest, String passwd) { + return zip(src, dest, true, passwd); + } + + /** + * 使用给定密码压缩指定文件或文件夹到指定位置. + *

+ * dest可传最终压缩文件存放的绝对路径,也可以传存放目录,也可以传null或者"".
+ * 如果传null或者""则将压缩文件存放在当前目录,即跟源文件同目录,压缩文件名取源文件名,以.zip为后缀;
+ * 如果以路径分隔符(File.separator)结尾,则视为目录,压缩文件名取源文件名,以.zip为后缀,否则视为文件名. + * + * @param src + * 要压缩的文件或文件夹路径 + * @param dest + * 压缩文件存放路径 + * @param isCreateDir + * 是否在压缩文件里创建目录,仅在压缩文件为目录时有效.
+ * 如果为false,将直接压缩目录下文件到压缩文件. + * @param passwd + * 压缩使用的密码 + * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. + */ + public static String zip(String src, String dest, boolean isCreateDir, + String passwd) { + File srcFile = new File(src); + dest = buildDestinationZipFilePath(srcFile, dest); + ZipParameters parameters = new ZipParameters(); + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 压缩方式 + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 压缩级别 + if (!StringUtils.isEmpty(passwd)) { + parameters.setEncryptFiles(true); + parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式 + parameters.setPassword(passwd.toCharArray()); + } + try { + ZipFile zipFile = new ZipFile(dest); + if (srcFile.isDirectory()) { + // 如果不创建目录的话,将直接把给定目录下的文件压缩到压缩文件,即没有目录结构 + if (!isCreateDir) { + File[] subFiles = srcFile.listFiles(); + ArrayList temp = new ArrayList(); + Collections.addAll(temp, subFiles); + zipFile.addFiles(temp, parameters); + return dest; + } + zipFile.addFolder(srcFile, parameters); + } else { + zipFile.addFile(srcFile, parameters); + } + return dest; + } catch (ZipException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 构建压缩文件存放路径,如果不存在将会创建 传入的可能是文件名或者目录,也可能不传,此方法用以转换最终压缩文件的存放路径 + * + * @param srcFile + * 源文件 + * @param destParam + * 压缩目标路径 + * @return 正确的压缩文件存放路径 + */ + private static String buildDestinationZipFilePath(File srcFile, + String destParam) { + if (StringUtils.isEmpty(destParam)) { + if (srcFile.isDirectory()) { + destParam = srcFile.getParent() + File.separator + + srcFile.getName() + ".zip"; + } else { + String fileName = srcFile.getName().substring(0, + srcFile.getName().lastIndexOf(".")); + destParam = srcFile.getParent() + File.separator + fileName + + ".zip"; + } + } else { + createDestDirectoryIfNecessary(destParam); // 在指定路径不存在的情况下将其创建出来 + if (destParam.endsWith(File.separator)) { + String fileName = ""; + if (srcFile.isDirectory()) { + fileName = srcFile.getName(); + } else { + fileName = srcFile.getName().substring(0, + srcFile.getName().lastIndexOf(".")); + } + destParam += fileName + ".zip"; + } + } + return destParam; + } + + /** + * 在必要的情况下创建压缩文件存放目录,比如指定的存放路径并没有被创建 + * + * @param destParam + * 指定的存放路径,有可能该路径并没有被创建 + */ + private static void createDestDirectoryIfNecessary(String destParam) { + File destDir = null; + if (destParam.endsWith(File.separator)) { + destDir = new File(destParam); + } else { + destDir = new File(destParam.substring(0, + destParam.lastIndexOf(File.separator))); + } + if (!destDir.exists()) { + destDir.mkdirs(); + } + } + + /** + * 删除压缩文件中的目录 + * + * @param file + * 目标zip文件 + * @param removeDir + * 要移除的目录 + * @param charset + * 编码 + * @throws ZipException + */ + @SuppressWarnings("rawtypes") + private static void removeDirFromZipArchive(String file, String removeDir, + String charset) throws ZipException { + // 创建ZipFile并设置编码 + ZipFile zipFile = new ZipFile(file); + + if (null != charset || !"".equals(charset)) { + zipFile.setFileNameCharset(charset); + } + + // 给要删除的目录加上路径分隔符 + if (!removeDir.endsWith(File.separator)) + removeDir += File.separator; + + // 如果目录不存在, 直接返回 + FileHeader dirHeader = zipFile.getFileHeader(removeDir); + if (null == dirHeader) + return; + + // 遍历压缩文件中所有的FileHeader, 将指定删除目录下的子文件名保存起来 + List headersList = zipFile.getFileHeaders(); + List removeHeaderNames = new ArrayList(); + for (int i = 0, len = headersList.size(); i < len; i++) { + FileHeader subHeader = (FileHeader) headersList.get(i); + if (subHeader.getFileName().startsWith(dirHeader.getFileName()) + && !subHeader.getFileName().equals(dirHeader.getFileName())) { + removeHeaderNames.add(subHeader.getFileName()); + } + } + // 遍历删除指定目录下的所有子文件, 最后删除指定目录(此时已为空目录) + for (String headerNameString : removeHeaderNames) { + zipFile.removeFile(headerNameString); + } + zipFile.removeFile(dirHeader); + } + + /** + * 打印zip文件信息 + * + * @param path + */ + public static void printZipInfo(String path) { + try { + ZipFile zipFile = new ZipFile(path); + List fileHeaderList = zipFile.getFileHeaders(); + for (int i = 0; i < fileHeaderList.size(); i++) { + FileHeader fileHeader = (FileHeader) fileHeaderList.get(i); + // FileHeader包含zip文件中对应文件的很多属性 + System.out.println("****File Details for: " + fileHeader.getFileName() + "*****"); + System.out.println("文件名: " + fileHeader.getFileName()); + System.out.println("是否为目录: " + fileHeader.isDirectory()); + System.out.println("压缩后大小: " + fileHeader.getCompressedSize()); + System.out.println("未压缩大小: " + fileHeader.getUncompressedSize()); + System.out.println("************************************************************"); + } + } catch (ZipException e) { + e.printStackTrace(); + } + + } + +} \ No newline at end of file diff --git a/javase-tutorials/src/main/java/org/javase/tutorials/zip4j/Zip4j.java b/javase-tutorials/src/main/java/org/javase/tutorials/zip4j/Zip4j.java new file mode 100644 index 0000000..d90c8e5 --- /dev/null +++ b/javase-tutorials/src/main/java/org/javase/tutorials/zip4j/Zip4j.java @@ -0,0 +1,215 @@ +package org.javase.tutorials.zip4j; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; + +import net.lingala.zip4j.core.ZipFile; +import net.lingala.zip4j.exception.ZipException; +import net.lingala.zip4j.model.ZipParameters; +import net.lingala.zip4j.util.Zip4jConstants; + +import org.junit.Before; +import org.junit.Test; + +/** + * 使用zip4j压缩或解压文件 + * @author 冯靖 + * + */ +public class Zip4j { + + + @Before + public void setup() throws Exception{ + ZipFile zipFile = new ZipFile("src/main/resources/AddFilesDeflateComp.zip"); + if(zipFile.getFile().exists()){ + zipFile.getFile().delete(); + } + } + + + /** + * 示例1 创建压缩包添加文件到压缩包中(未设置加密) + */ + @Test + public void example1(){ + try { + + ZipFile zipFile = new ZipFile("src/main/resources/AddFilesDeflateComp.zip"); + + ArrayList filesToAdd = new ArrayList(); + filesToAdd.add(new File("src/main/resources/sample.txt")); + filesToAdd.add(new File("src/main/resources/zip4j.txt")); + filesToAdd.add(new File("src/main/resources/zip4j-1.3.2.jar")); + + ZipParameters parameters = new ZipParameters(); + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // set compression method to deflate compression + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); + zipFile.addFiles(filesToAdd, parameters); + + CompressUtil.printZipInfo("src/main/resources/AddFilesDeflateComp.zip"); + + + } catch (ZipException e) { + e.printStackTrace(); + } + } + + + /** + * 示例2 创建压缩包添加文件到指定目录中进行压缩 + */ + @Test + public void example2(){ + try { + ZipFile zipFile = new ZipFile("src/main/resources/AddFilesDeflateComp.zip"); + ArrayList filesToAdd = new ArrayList(); + filesToAdd.add(new File("src/main/resources/sample.txt")); + filesToAdd.add(new File("src/main/resources/zip4j.txt")); + filesToAdd.add(new File("src/main/resources/zip4j-1.3.2.jar")); + + ZipParameters parameters = new ZipParameters(); + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); + + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); + parameters.setRootFolderInZip("target/"); + + zipFile.addFiles(filesToAdd, parameters); + } catch (ZipException e) { + e.printStackTrace(); + } + } + + /** + * 示例3 添加文件夹到压缩包中 + */ + @Test + public void example3(){ + try { + + ZipFile zipFile = new ZipFile("src/main/resources/AddFolder.zip"); + String folderToAdd = "src/main/resources"; + + ZipParameters parameters = new ZipParameters(); + + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); + zipFile.addFolder(folderToAdd, parameters); + + } catch (ZipException e) { + e.printStackTrace(); + } + } + + /** + * 示例4 创建加密压缩包 + */ + @Test + public void example4(){ + try { + ZipFile zipFile = new ZipFile("src/main/resources/AddFilesWithAESZipEncryption.zip"); + + ArrayList filesToAdd = new ArrayList(); + filesToAdd.add(new File("src/main/resources/sample.txt")); + filesToAdd.add(new File("src/main/resources/zip4j.txt")); + filesToAdd.add(new File("src/main/resources/zip4j-1.3.2.jar")); + + ZipParameters parameters = new ZipParameters(); + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); + + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); + parameters.setEncryptFiles(true); + + parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES); + + + parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256); + parameters.setPassword("123456"); + + zipFile.addFiles(filesToAdd, parameters); + } catch (ZipException e) { + e.printStackTrace(); + } + } + + /** + * 示例5 创建分卷压缩包 + */ + @Test + public void example5(){ + try { + + ZipFile zipFile = new ZipFile("src/main/resources/CreateSplitZipFile.zip"); + + ArrayList filesToAdd = new ArrayList(); + filesToAdd.add(new File("src/main/resources/sample.txt")); + filesToAdd.add(new File("src/main/resources/zip4j.txt")); + filesToAdd.add(new File("src/main/resources/zip4j-1.3.2.jar")); + + ZipParameters parameters = new ZipParameters(); + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); + + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); + + zipFile.createZipFile(filesToAdd, parameters, true, 65536); + } catch (ZipException e) { + e.printStackTrace(); + } + } + + /** + * 示例6 通过流的方式添加文件到压缩包中 + */ + @Test + public void example6(){ + InputStream is = null; + + try { + ZipFile zipFile = new ZipFile("src/main/resources/AddStreamToZip.zip"); + + ZipParameters parameters = new ZipParameters(); + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); + parameters.setFileNameInZip("sample.txt"); + parameters.setSourceExternalStream(true); + + is = new FileInputStream("src/main/resources/sample.txt"); + zipFile.addStream(is, parameters); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + + /** + * 示例7 解压压缩文件 + */ + @Test + public void example7(){ + + example4(); + + try { + ZipFile zipFile = new ZipFile("src/main/resources/AddFilesWithAESZipEncryption.zip"); + if (zipFile.isEncrypted()) { + // if yes, then set the password for the zip file + zipFile.setPassword("123456"); + zipFile.extractAll("src/main/resources/zipfile"); + } + } catch (ZipException e) { + e.printStackTrace(); + } + } + +} diff --git a/javase-tutorials/src/main/resources/example.jpg b/javase-tutorials/src/main/resources/example.jpg new file mode 100644 index 0000000..f213a75 Binary files /dev/null and b/javase-tutorials/src/main/resources/example.jpg differ diff --git a/javase-tutorials/src/main/resources/sample.txt b/javase-tutorials/src/main/resources/sample.txt new file mode 100644 index 0000000..325313f --- /dev/null +++ b/javase-tutorials/src/main/resources/sample.txt @@ -0,0 +1,51 @@ +ZIP4J 是一个支持处理ZIP文件的开源库 +支持创建,修改,添加,删除,解压 压缩文件 +支持读/写密码保护 +支持AES加密 128/256 +支持标准ZIP加密 +支持进度监视器 +自持Unicode 文件名 +支持创建分卷压缩文件 +支持将文件添加到压缩包中但不进行压缩 + + +Create, Add, Extract, Update, Remove files from a Zip file +针对ZIP压缩文件创建、添加、抽出、更新和移除文件 +Read/Write password protected Zip files +(读写有密码保护的Zip文件) +Supports AES 128/256 Encryption +(支持AES 128/256算法加密) +Supports Standard Zip Encryption +(支持标准Zip算法加密) +Supports Zip64 format +(支持zip64格式) +Supports Store (No Compression) and Deflate compression method +(支持Store(非压缩)和Deflate压缩方法---不太明白) +Create or extract files from Split Zip files (Ex: z01, z02,...zip) +(针对分块zip文件创建和抽出文件) +Supports Unicode file names +(支持Unicode编码文件名) +Progress Monitor +(进度监控) + +压缩效率 + + ZIP4J提供5中压缩算法: + + DEFLATE_LEVEL_FASTEST + DEFLATE_LEVEL_FASTEST + DEFLATE_LEVEL_NORMAL + DEFLATE_LEVEL_MAXIMUM + DEFLATE_LEVEL_ULTRA + 根据API提供的几种不同压缩级别进行测试(文件夹压缩),测试结果如下: + + 一个180M的文件夹压缩后 + + WinRAR 30秒 - 78.7 MB ; + NORMAL - 18 秒 91.2 MB ; + FAST 13秒 -93.1 MB; + FASTEST - 最快速10 秒94.7 MB + MAXIMUM 23 秒 - 90.7 MB; + ULTRA -50 90.6 MB + +ZIP4J 项目地址为 :http://www.lingala.net/zip4j/ \ No newline at end of file diff --git a/javase-tutorials/src/main/resources/watermark.png b/javase-tutorials/src/main/resources/watermark.png new file mode 100644 index 0000000..c9c22b3 Binary files /dev/null and b/javase-tutorials/src/main/resources/watermark.png differ diff --git a/javase-tutorials/src/main/resources/zip4j-1.3.2.jar b/javase-tutorials/src/main/resources/zip4j-1.3.2.jar new file mode 100644 index 0000000..dcdf85e Binary files /dev/null and b/javase-tutorials/src/main/resources/zip4j-1.3.2.jar differ diff --git a/javase-tutorials/src/main/resources/zip4j.txt b/javase-tutorials/src/main/resources/zip4j.txt new file mode 100644 index 0000000..72f8529 --- /dev/null +++ b/javase-tutorials/src/main/resources/zip4j.txt @@ -0,0 +1,262 @@ +package org.javase.tutorials.zip4j; + + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +import net.lingala.zip4j.core.ZipFile; +import net.lingala.zip4j.exception.ZipException; +import net.lingala.zip4j.model.FileHeader; +import net.lingala.zip4j.model.ZipParameters; +import net.lingala.zip4j.util.Zip4jConstants; + +/** + * ZIP压缩文件操作工具类 + * 支持密码,默认采用UTF-8编码 + * 依赖zip4j开源项目(http://www.lingala.net/zip4j/) + * 版本1.3.2 + * @author ninemax + */ +public class CompressUtil { + + /** + * 使用给定密码解压指定的ZIP压缩文件到指定目录 + *

+ * 如果指定目录不存在,可以自动创建,不合法的路径将导致异常被抛出 + * @param zip 指定的ZIP压缩文件 + * @param dest 解压目录 + * @param passwd ZIP文件的密码 + * @return 解压后文件数组 + * @throws ZipException 压缩文件有损坏或者解压缩失败抛出 + */ + public static File [] unzip(String zip, String dest, String passwd) throws ZipException { + File zipFile = new File(zip); + return unzip(zipFile, dest, passwd); + } + + /** + * 使用给定密码解压指定的ZIP压缩文件到当前目录 + * @param zip 指定的ZIP压缩文件 + * @param passwd ZIP文件的密码 + * @return 解压后文件数组 + * @throws ZipException 压缩文件有损坏或者解压缩失败抛出 + */ + public static File [] unzip(String zip, String passwd) throws ZipException { + File zipFile = new File(zip); + File parentDir = zipFile.getParentFile(); + return unzip(zipFile, parentDir.getAbsolutePath(), passwd); + } + + /** + * 使用给定密码解压指定的ZIP压缩文件到指定目录 + *

+ * 如果指定目录不存在,可以自动创建,不合法的路径将导致异常被抛出 + * @param zip 指定的ZIP压缩文件 + * @param dest 解压目录 + * @param passwd ZIP文件的密码 + * @return 解压后文件数组 + * @throws ZipException 压缩文件有损坏或者解压缩失败抛出 + */ + public static File [] unzip(File zipFile, String dest, String passwd) throws ZipException { + ZipFile zFile = new ZipFile(zipFile); + zFile.setFileNameCharset("GBK"); + if (!zFile.isValidZipFile()) { + throw new ZipException("压缩文件不合法,可能被损坏."); + } + File destDir = new File(dest); + if (destDir.isDirectory() && !destDir.exists()) { + destDir.mkdir(); + } + if (zFile.isEncrypted()) { + zFile.setPassword(passwd.toCharArray()); + } + zFile.extractAll(dest); + + List headerList = zFile.getFileHeaders(); + List extractedFileList = new ArrayList(); + for(FileHeader fileHeader : headerList) { + if (!fileHeader.isDirectory()) { + extractedFileList.add(new File(destDir,fileHeader.getFileName())); + } + } + File [] extractedFiles = new File[extractedFileList.size()]; + extractedFileList.toArray(extractedFiles); + return extractedFiles; + } + + /** + * 压缩指定文件到当前文件夹 + * @param src 要压缩的指定文件 + * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. + */ + public static String zip(String src) { + return zip(src,null); + } + + /** + * 使用给定密码压缩指定文件或文件夹到当前目录 + * @param src 要压缩的文件 + * @param passwd 压缩使用的密码 + * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. + */ + public static String zip(String src, String passwd) { + return zip(src, null, passwd); + } + + /** + * 使用给定密码压缩指定文件或文件夹到当前目录 + * @param src 要压缩的文件 + * @param dest 压缩文件存放路径 + * @param passwd 压缩使用的密码 + * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. + */ + public static String zip(String src, String dest, String passwd) { + return zip(src, dest, true, passwd); + } + + /** + * 使用给定密码压缩指定文件或文件夹到指定位置. + *

+ * dest可传最终压缩文件存放的绝对路径,也可以传存放目录,也可以传null或者"".
+ * 如果传null或者""则将压缩文件存放在当前目录,即跟源文件同目录,压缩文件名取源文件名,以.zip为后缀;
+ * 如果以路径分隔符(File.separator)结尾,则视为目录,压缩文件名取源文件名,以.zip为后缀,否则视为文件名. + * @param src 要压缩的文件或文件夹路径 + * @param dest 压缩文件存放路径 + * @param isCreateDir 是否在压缩文件里创建目录,仅在压缩文件为目录时有效.
+ * 如果为false,将直接压缩目录下文件到压缩文件. + * @param passwd 压缩使用的密码 + * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. + */ + public static String zip(String src, String dest, boolean isCreateDir, String passwd) { + File srcFile = new File(src); + dest = buildDestinationZipFilePath(srcFile, dest); + ZipParameters parameters = new ZipParameters(); + parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 压缩方式 + parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 压缩级别 + if (!StringUtils.isEmpty(passwd)) { + parameters.setEncryptFiles(true); + parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式 + parameters.setPassword(passwd.toCharArray()); + } + try { + ZipFile zipFile = new ZipFile(dest); + if (srcFile.isDirectory()) { + // 如果不创建目录的话,将直接把给定目录下的文件压缩到压缩文件,即没有目录结构 + if (!isCreateDir) { + File [] subFiles = srcFile.listFiles(); + ArrayList temp = new ArrayList(); + Collections.addAll(temp, subFiles); + zipFile.addFiles(temp, parameters); + return dest; + } + zipFile.addFolder(srcFile, parameters); + } else { + zipFile.addFile(srcFile, parameters); + } + return dest; + } catch (ZipException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 构建压缩文件存放路径,如果不存在将会创建 + * 传入的可能是文件名或者目录,也可能不传,此方法用以转换最终压缩文件的存放路径 + * @param srcFile 源文件 + * @param destParam 压缩目标路径 + * @return 正确的压缩文件存放路径 + */ + private static String buildDestinationZipFilePath(File srcFile,String destParam) { + if (StringUtils.isEmpty(destParam)) { + if (srcFile.isDirectory()) { + destParam = srcFile.getParent() + File.separator + srcFile.getName() + ".zip"; + } else { + String fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf(".")); + destParam = srcFile.getParent() + File.separator + fileName + ".zip"; + } + } else { + createDestDirectoryIfNecessary(destParam); // 在指定路径不存在的情况下将其创建出来 + if (destParam.endsWith(File.separator)) { + String fileName = ""; + if (srcFile.isDirectory()) { + fileName = srcFile.getName(); + } else { + fileName = srcFile.getName().substring(0, srcFile.getName().lastIndexOf(".")); + } + destParam += fileName + ".zip"; + } + } + return destParam; + } + + /** + * 在必要的情况下创建压缩文件存放目录,比如指定的存放路径并没有被创建 + * @param destParam 指定的存放路径,有可能该路径并没有被创建 + */ + private static void createDestDirectoryIfNecessary(String destParam) { + File destDir = null; + if (destParam.endsWith(File.separator)) { + destDir = new File(destParam); + } else { + destDir = new File(destParam.substring(0, destParam.lastIndexOf(File.separator))); + } + if (!destDir.exists()) { + destDir.mkdirs(); + } + } + + + /** + * 删除压缩文件中的目录 + * @param file 目标zip文件 + * @param removeDir 要移除的目录 + * @throws ZipException + */ + @SuppressWarnings("rawtypes") + private static void removeDirFromZipArchive(String file, String removeDir) throws ZipException { + // 创建ZipFile并设置编码 + ZipFile zipFile = new ZipFile(file); + zipFile.setFileNameCharset("GBK"); + + // 给要删除的目录加上路径分隔符 + if (!removeDir.endsWith(File.separator)) removeDir += File.separator; + + // 如果目录不存在, 直接返回 + FileHeader dirHeader = zipFile.getFileHeader(removeDir); + if (null == dirHeader) return; + + // 遍历压缩文件中所有的FileHeader, 将指定删除目录下的子文件名保存起来 + List headersList = zipFile.getFileHeaders(); + List removeHeaderNames = new ArrayList(); + for(int i=0, len = headersList.size(); i