Apache Common包简介
Apache Commons是对JDK的拓展,包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动。官网网址:http://commons.apache.org
Common包包含哪些类?
请参考:Apache Common官方网站
常用包梳理
| 包名 | 介绍 |
| ————- |:————-:|
| commons-lang | 提供字符串处理、数值处理、对象等工具方法 |
| commons-collections | 集合工具类,用来操作各种集合 |
| commons-io | IO流操作的工具类 |
| commons-beanutils | Java Bean 操作和封装工具 |
| commons-dbcp2 | 数据库连接池实现 |
| commons-pool2 | 对象池实现,用于数据库连接池等 |
| commons-fileupload | HTML文件上传工具 |
| commons-codec | 编码/解码算法,如Base64、Hex、MD5等 |
| commons-net | 网络工具,如FTP、Telnet、DNS等 |
| commons-configuration | 配置文件解析器 |
| commons-vfs | 虚拟文件系统,对各种文件系统的包装|
| commons-digester | XML解析器 |
| commons-logging | 日志记录器抽象层|
| commons-validator | 数据校验器|
Commons BeanUtils
针对Bean的一个工具集。由于Bean往往是有一堆get和set组成,所以BeanUtils也是在此基础上进行一些包装。它利用Java的反射机制,从动态的生成对bean的getter和setter的调用代码,到模拟创建一个动态的bean,等等。
这个包看似简单,却是很多开源项目的基石:如在著名的Struts和Spring Framework中,我们都能找到BeanUtils的影子。大家猜猜看,有哪位名人是BeanUtils的作者之一?没错,就是Struts的创始人Craig McClanahan。
一个比较常用的功能是Bean Copy,也就是copy bean的属性。如果做分层架构开发的话就会用到,比如从PO(Persistent Object)拷贝数据到VO(Value Object)。
模块介绍
包名 | 介绍 |
---|
beanutils | 核心包,主要是一些常用的工具类及接口定义 |
converters | 转换String到需要类型的类,实现Converter接口 |
| 这些转换器实现了 LocaleConverter 接口,并提供了根据本地语言环境格式化对象到字符串以及解析字符串到对象的功能。 主要用途是: 国际化: 根据不同语言环境解析和格式化数值 本地化的 Bean 操作: 解析不同本地语言环境的请求参数到 Bean |
expression | 统一的表达式语言接口,定义表达式解析、求值和设置属性值等方法。 |
代码案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| import lombok.Data; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.converters.DateConverter; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Map;
public class BeanUtilTest { @Test public void testCovertToInteger() { Object i = ConvertUtils.convert("123", Integer.class); if (i instanceof Integer) { System.out.println("it can cast to integer"); System.out.println("the number result is " + (Integer) i); } else { System.err.print("it can not cast to target Instance!"); } } @Test public void testConvertArrToIntegerArr() { Object convert = ConvertUtils.convert(new String[]{"1", "2", "3"}, Integer.class); if (convert instanceof Integer[]) { System.out.println("it can cast to Integer Array"); Integer[] integers = (Integer[]) convert; Arrays.stream(integers).forEach(System.out::println); } else { System.err.print("it can not cast to target Instance!"); } } @Test public void testCovertToDate () { DateConverter dateConverter = new DateConverter(); dateConverter.setPatterns(new String[]{"yyyy-MM-dd","yyyy-MM-dd HH:mm:ss"}); ConvertUtils.register(dateConverter, Date.class); Object convert = ConvertUtils.convert("2023-12-01", Date.class); System.out.println(convert); System.out.println(ConvertUtils.convert("2023-06-30 09:53:55", Date.class)); } @Test public void testBeanUtil() throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException { Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "will"); map.put("age", "18"); Person p = new Person(); BeanUtils.populate(p, map); System.out.println("p is " + p); Person p1 = new Person(); BeanUtils.copyProperties(p1, p); System.out.println("p1 is " + p1); Person p2 = new Person(); BeanUtils.copyProperty(p2,"name","will_yang"); System.out.println("p2 is " + p2); BeanUtils.setProperty(p2, "age", 20); System.out.println("p2 is " + p2); Object bean = BeanUtils.cloneBean(p2); System.out.println("bean = " + bean); } @Data public static class Person{ private String name; private String age; } }
|
Commons Codec
是编码和解码组件,提供常用的编码和解码方法,如DES、SHA1、MD5、Base64、URL和Soundx等。
二进制相关
二进制包主要提供16进制、Base64、Base32等的编解码工具类。
16进制(Hex类)
十六进制常用于将二进制以更简短的方式展示,比如MD5是128位,展现起来太长,而转换为16进制后只需要32个字符即可表示出来。
示例代码如下:
1 2 3 4 5 6
| String hex = Hex.encodeHexString("123".getBytes()); System.out.println(hex);
byte[] src = Hex.decodeHex(hex); System.out.println(new String(src));
|
2. Base64,Base32,Base16
Base64是网络上最常见的用于传输二进制数据的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。Base32就是使用32个可打印字符,Base16就是使用16个(实际上相当于16进制)。
| | |
---|
名称 | 编码表字符串 | 位数不足是否会补全 = |
base16 | 数字09 和 字母 AF | 不会,位数刚好是 4 的倍数 |
base32 | 大写字母AZ 和 数字27 | 会 |
base64 | Base大写字母A-Z,小写字母a-z,数字0~9以及”+”,”/“ | 会 |
1 2 3 4 5 6 7 8 9 10
| String base64 = Base64.encodeBase64String("测试".getBytes()); System.out.println(base64);
byte[] src = Base64.decodeBase64(base64); System.out.println(new String(src));
Base64.isBase64(base64);
|
Codec还提供了Base系列的流处理,以流的方式去处理Base编解码,示例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
InputStream is = new ByteArrayInputStream("123".getBytes()); Base64InputStream ebis = new Base64InputStream(is, true); String enc = IOUtils.toString(ebis, "UTF-8");
is = new ByteArrayInputStream(enc.getBytes()); Base64InputStream dbis = new Base64InputStream(is, false); String dec = IOUtils.toString(dbis, "UTF-8");
final String data = "123"; ByteArrayOutputStream baos = new ByteArrayOutputStream(); Base64OutputStream ebos = new Base64OutputStream(baos, true); IOUtils.write(data, ebos, "UTF-8"); String enc2 = baos.toString();
baos = new ByteArrayOutputStream(); Base64OutputStream dbos = new Base64OutputStream(baos, false); IOUtils.write(data, dbos, "UTF-8"); String dec2 = dbos.toString();
|
URL相关
URL之所以要进行编码,是因为URL中有些字符会引起歧义。
例如URL参数字符串中使用key=value键值对这样的形式来传参,键值对之间以&符号分隔,如/s?q=abc&ie=utf-8。如果你的value字符串中包含了=或者&,那么势必会造成接收URL的服务器解析错误,因此必须将引起歧义的&和=符号进行转义,也就是对其进行编码。
又如URL的编码格式采用的是ASCII码,而不是Unicode,这也就是说你不能在URL中包含任何非ASCII字符,例如中文。否则如果客户端浏览器和服务端浏览器支持的字符集不同的情况下,中文可能会造成问题。
URL编码的原则就是使用安全的字符(没有特殊用途或者特殊意义的可打印字符)去表示那些不安全的字符。
编解码示例代码如下:
1 2 3 4 5 6 7
| URLCodec urlCodec = new URLCodec();
String encUrl = urlCodec.encode("http://x.com?f=哈"); System.out.println(encUrl);
String decUrl = urlCodec.decode(encUrl); System.out.println(decUrl);
|
摘要算法
摘要算法是一种单向的散列算法,它满足以下几个特点。
- 输入长度是任意的
- 输出长度是固定的
- 对每一个给定的输入,计算输出是很容易的
- 不可逆,无法通过输出推算出原数据
- 输出不依赖于输入。就是输入数据变动一个字节结果会相差很多
由于摘要算法以上特点,主要用于数据完整性校验。例如网上的资源一般会提供一个摘要值(一般用MD5算法),用户下载后可以通过工具对资源做MD5后和网上给定的值比较,如果不一致说明文件不完整了,可能是下载过程网络波动内容有丢失,也可能被人篡改过。
也可以做数据的指纹,比如网盘秒传,就是利用摘要值做判断。客户端上传前先对文件做摘要值,传给服务端,服务端发现有相同摘要的文件说明两个文件内容是一致的,这样就无需上传直接将文件存储路径指向这个文件就可以了,既实现了秒传,还节约了服务器磁盘空间(不同用户相同内容的文件实际上指向的是同一份文件)。
很多系统也将密码做md5后存储,其中这种方式并不安全。md5已经很很多公开结果了,并且使用彩虹表碰撞也很容易破解了。所以并不建议使用md5存储密码。密码推荐使用BCrypt算法。
摘要算法主要有以下几个
- MD(Message Digest):消息摘要
- SHA(Secure Hash Algorithm):安全散列
- MAC(Message Authentication Code):消息认证码
1. MD系列
主要有MD2、MD4、MD5,目前一般常用MD5
1 2 3 4
|
String md5 = DigestUtils.md5Hex("测试");
|
2. SHA系列
SHA系列有SHA-1、SHA-224、SHA-256、SHA-384、SHA-512,SHA3-224、SHA3-256、SHA3-384、SHA3-512等。目前安全起见一般选择256以上,推荐384以上。当然摘要越长则计算耗时也越长,需要根据需求权衡。
1 2 3 4 5 6 7 8
| String sha1 = DigestUtils.sha1Hex("测试"); String sha256 = DigestUtils.sha256Hex("测试"); String sha384 = DigestUtils.sha384Hex("测试"); String sha512 = DigestUtils.sha512Hex("测试"); String sha3_256 = DigestUtils.sha3_256Hex("测试"); String sha3_384 = DigestUtils.sha3_384Hex("测试"); String sha3_512 = DigestUtils.sha3_512Hex("测试");
|
3. HMAC系列
HMAC(keyed-Hash Message Authentication Code)系列是包含密钥的散列算法,包含了MD和SHA两个系列的消息摘要算法。融合了MD,SHA:
MD系列:HMacMD2,HMacMD4,HMacMD5
SHA系列:HMacSHA1,HMacSHA224,HMacSHA256,HMacSHA38
,HMacSHA512
1 2 3 4 5 6 7 8
| String key = "asdf3234asdf3234asdf3234asdf3234"; String valueToDigest = "测试数据";
String hmacMd5 = new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
String hmacSha256 = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest); String hmacSha384 = new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest); String hmacSha512 = new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
|
Commons Collections
Apache Commons Collections 是对 java.util.Collection 的扩展。
目前 Collections 包有两个:
- commons-collections
- commons-collections4
commons-collections 最新版本是3.2.2,不支持泛型,目前官方已不在维护。
collections4 目前最新版本是4.4,最低要求 Java8 以上。
相对于 collections 来说完全支持 Java8 的特性并且支持泛型,该版本无法兼容旧有版本,于是为了避免冲突改名为 collections4。推荐直接使用该版本。(注:两个版本可以共存,使用时需要注意)。
这里使用3.2.2版本的中包名做下介绍:
包名 | 介绍 |
---|
collections | CommonsCollections自定义的一组公用的接口和工具类 |
bag | 实现Bag接口的一组类 |
bidimap | 实现BidiMap系列接口的一组类 |
buffer | 实现Buffer接口的一组类 |
collection | 实现java.util.Collection接口的一组类 |
comparators | 实现java.util.Comparator接口的一组类 |
functors | Commons Collections自定义的一组功能类 |
iterators | 实现java.util.Iterator接口的一组类 |
keyvalue | 实现集合和键/值映射相关的一组类 |
list | 实现java.util.List接口的一组类 |
map | 实现Map系列接口的一组类 |
set | 实现Set系列接口的一组类 |
工具类
CollectionUtils
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| String str = null; List list1 = Arrays.asList(new String[]{"1", "2", "3"}); List list2 = Arrays.asList(new String[]{"1", "2", "4"});
CollectionUtils.isEmpty(list1);
CollectionUtils.addIgnoreNull(list1, str);
CollectionUtils.containsAll(list1, list2);
CollectionUtils.containsAny(list1, list2);
CollectionUtils.subtract(list1, list2);
CollectionUtils.union(list1, list2);
CollectionUtils.intersection(list1, list2);
|
ListUtils
1 2 3 4 5 6 7 8 9 10 11 12
| List list1 = Arrays.asList(new String[]{"1", "2", "3"}); List list2 = Arrays.asList(new String[]{"1", "2", "4"});
ListUtils.subtract(list1, list2); ListUtils.union(list1, list2); ListUtils.intersection(list1, list2);
ListUtils.isEqualList(list1, list2);
ListUtils.emptyIfNull(list1);
ListUtils.hashCodeForList(list1);
|
除了以上介绍了两个还有 MapUtils,SetUtils,EnumerationUtils,IterableUtils 等不是很常用就不多做介绍了。
集合扩展
FixedSizeList
FixedSizeList 用于装饰另一个 List 以阻止修改其大小。不支持添加、删除、清除等操作。set 方法是允许的(因为它不会改变列表大小),下面看代码示例
1 2 3 4 5 6 7 8 9 10
| List<String> sourceList = new ArrayList<>(); sourceList.add("1");
List<String> list = FixedSizeList.fixedSizeList(sourceList); list.set(0, "11"); println(list);
list.add("4"); list.remove("5"); list.clear();
|
SetUniqueList
SetUniqueList 用来装饰另一个 List 以确保不存在重复元素,内部使用了 Set 来判断重复问题
1 2 3 4 5 6 7 8
| List<String> sourceList = new ArrayList<>(); sourceList.add("1"); sourceList.add("2");
SetUniqueList<String> list = SetUniqueList.setUniqueList(sourceList);
list.add("2"); println(list);
|
TransformedList 装饰另一个 List 以转换添加的对象。add 和 set 方法受此类影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| List<String> sourceList = new ArrayList<>(); sourceList.add("1"); sourceList.add("2");
TransformedList<String> list = TransformedList.transformingList(sourceList, e -> e.concat("_")); list.add("a"); println(list);
list = TransformedList.transformedList(sourceList, e -> e.concat("_")); list.add("a"); println(list);
|
PredicatedList
PredicatedList 装饰另一个 List ,装饰后的 List 在添加元素的时候会调用 Predicate 接口来判断元素,匹配通过才会被添加到集合中。
1 2 3 4 5 6 7 8
| List<String> sourceList = new ArrayList<>();
PredicatedList<String> list = PredicatedList.predicatedList(new ArrayList<>(), e -> e.startsWith("_")); list.add("_4"); println(list);
list.add("4");
|
ListOrderedSet
ListOrderedSet 有序的Set,顺序按照元素添加顺序排列,类似 List
1 2 3 4 5 6
| Set<String> set = new ListOrderedSet<>(); set.add("aa"); set.add("11"); set.add("哈哈"); println(set);
|
Bag
Bag 接口是带计数功能的集合扩展,它继承了 Collection 接口,可以当做集合来使用
1 2 3 4 5 6 7
| Bag<String> bag = new HashBag<>(); bag.add("a"); bag.add("b"); bag.add("a"); println(bag.size()); println(bag.getCount("a"));
|
Map扩展
MultiValuedMap
MultiValuedMap 和正常的 Map 有点区别,同一个 key 允许存放多个 value,这些 value 会放到一个 List 中。这个功能如果用 Java 的 Map 我们需要构造一个 Map<String, List<String>>
加个各种操作来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ListValuedMap<String, String> map = new ArrayListValuedHashMap<>(); map.put("user", "张三"); map.put("user", "李四"); map.put("user", "张三"); map.put("age", "12");
List<String> users2 = map.get("user");
map.containsKey("user"); map.containsValue("张三"); map.containsMapping("user", "张三");
int size = map.size();
Collection<String> ss = map.values(); map.remove("user");
Map<String, Collection<String>> jMap = map.asMap();
|
CaseInsensitiveMap
key大小写不敏感的Map
1 2 3 4 5 6
| Map<String, Integer> map = new CaseInsensitiveMap<>(); map.put("one", 1); map.put("two", 2); Integer o = map.get("ONE"); println(o);
|
OrderedMap
有顺序的 Map,按照插入顺序排序。如果使用 hashMap 的话 key 会按照 hash 值排序,可能和插入顺序一样,也可能不一样。key 数量和不同 JDK 版本都可能影响顺序,这是由于不同版本 jdk map 的 hash 算法有区别,hash 算法和当前 map 的容量也有关系。
1 2 3 4 5 6 7 8 9 10
| OrderedMap<String, String> map = new ListOrderedMap<>(); map.put("哈哈", "1"); map.put("此处", "2"); map.put("cc", "3"); map.put("dd", "4");
Set<String> set = map.keySet(); String nk = map.nextKey("此处"); String pk = map.previousKey("此处");
|
LRUMap
LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
各种缓存框架都有对 LRU 算法的支持,如 EhCache,GuavaCache,Redis 等,可以说是很常用的一种算法
1 2 3 4 5 6 7 8 9 10
| LRUMap<String, String> map = new LRUMap<>(2); map.put("aa", "1"); map.put("bb", "2"); map.put("cc", "3");
println(map);
map.get("bb"); map.put("dd", "4"); println(map);
|
PassiveExpiringMap
装饰一个 Map 以在达到过期时间时删除过期条目。当在 Map 中放置键值对时,此装饰器使用 ExpirationPolicy 来确定条目应保持多长时间,由到期时间值定义。当对 Map 做操作的时候才会检查元素是否过期并触发删除操作。
1 2 3 4 5 6 7 8 9 10 11
| int ttlMillis = 1000; PassiveExpiringMap.ExpirationPolicy<String, String> ep = new PassiveExpiringMap.ConstantTimeToLiveExpirationPolicy<>(ttlMillis); PassiveExpiringMap<String, String> map = new PassiveExpiringMap<>(ep); map.put("a", "1"); map.put("b", "2"); map.put("c", "3");
Thread.sleep(1000); String vc = map.get("c"); println(vc);
|
6. ReferenceMap
ReferenceMap 允许垃圾收集器删除映射。可以指定使用什么类型的引用来存储映射的键和值。如果使用的不是强引用,则垃圾收集器可以在键或值变得不可访问,或者 JVM 内存不足时删除映射。用它做一个简易的缓存不会导致存放内容过多导致内存溢出。
BidiMap
BidiMap 允许在 key 和 value 之间进行双向查找。其中一个键可以查找一个值,一个值可以同样轻松地查找一个键。这个接口扩展了 Map,value 不允许重复,如果重复将同时覆盖旧的键值对。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
BidiMap<String, String> map = new TreeBidiMap<>(); map.put("dog", "狗"); map.put("cat", "猫");
println(map); String key = map.getKey("狗"); println(key);
BidiMap<String, String> iMap = map.inverseBidiMap(); println(iMap); println(iMap.get("狗"));
iMap.put("鱼", "fish"); println(iMap); println(map);
|
Commons Compress
压缩、解压缩文件的组件,可以操作rar、cpio、Unix dump、tar、zip、gzip、XZ、Pack200和bzip2格式的压缩文件。
压缩
压缩:按某种算法减小文件所占用空间的大小
解压:按对应的逆向算法恢复文件
类名 | 作用 |
---|
GzipCompressorOutputStream | 压缩"*.gz “文件 |
GzipCompressorInputStream | 解压"*.gz “文件 |
BZip2CompressorOutputStream | 压缩"*.bz2 “文件 |
BZip2CompressorInputStream | 解压"*.bz2 “文件 |
XZCompressorOutputStream | 压缩"*.xz “文件 |
XZCompressorInputStream | 解压"*.xz “文件 |
FramedLZ4CompressorOutputStream | 压缩"*.lz4 “文件 |
FramedLZ4CompressorInputStream | 解压"*.lz4 “文件 |
BlockLZ4CompressorOutputStream | 压缩"*.block_lz4 “文件 |
BlockLZ4CompressorInputStream | 解压"*.block_lz4 “文件 |
Pack200CompressorOutputStream | 压缩"*.pack “文件 |
Pack200CompressorInputStream | 解压"*.pack “文件 |
DeflateCompressorOutputStream | 压缩"*.deflate “文件 |
DeflateCompressorInputStream | 解压"*.deflate “文件 |
LZMACompressorOutputStream | 压缩"*.lzma “文件 |
LZMACompressorInputStream | 解压"*.lzma “文件 |
FramedSnappyCompressorOutputStream | 压缩"*.sz “文件 |
FramedSnappyCompressorInputStream | 解压"*.sz “文件 |
ZCompressorInputStream | 解压"*.Z “文件 |
gzip
gzip是Unix,Linux上常用的压缩工具,也是当今的WEB站点上非常流行的压缩技术。其有压缩级别等概念,可以通过GzipParameters去设置。JDK8也自带了GZIPInputStream类,用法类似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| String file = "/test.js"; GzipParameters parameters = new GzipParameters(); parameters.setCompressionLevel(Deflater.BEST_COMPRESSION); parameters.setOperatingSystem(3); parameters.setFilename(FilenameUtils.getName(file)); parameters.setComment("Test file"); parameters.setModificationTime(System.currentTimeMillis()); FileOutputStream fos = new FileOutputStream(file + ".gz"); try (GzipCompressorOutputStream gzos = new GzipCompressorOutputStream(fos, parameters); InputStream is = new FileInputStream(file)) { IOUtils.copy(is, gzos); }
String gzFile = "/test.js.gz"; FileInputStream is = new FileInputStream(gzFile); try (GzipCompressorInputStream gis = new GzipCompressorInputStream(is)) { GzipParameters p = gis.getMetaData(); File targetFile = new File("/test.js"); FileUtils.copyToFile(gis, targetFile); targetFile.setLastModified(p.getModificationTime()); }
|
bz2
bz2是Linux下常见的压缩文件格式,是由具有高压缩率的压缩工具bzip2生成,以后缀为.bz2结尾的压缩文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| String srcFile = "/test.tar"; String targetFile = "/test.tar.bz2"; FileOutputStream os = new FileOutputStream(targetFile); try (BZip2CompressorOutputStream bzos = new BZip2CompressorOutputStream(os); InputStream is = new FileInputStream(srcFile)) { IOUtils.copy(is, bzos); }
String bzFile = "/test.tar.bz2"; FileInputStream is = new FileInputStream(bzFile); try (BZip2CompressorInputStream bzis = new BZip2CompressorInputStream(is)) { File targetFile = new File("test.tar"); FileUtils.copyToFile(bzis, targetFile); }
|
其他压缩算法的使用方式和bz2基本一致,这里就不做代码示例了。
归档
归档:将许多零散的文件整理为一个文件,文件总大小基本不变
解包:从归档文件中释放文件
类名 | 作用 |
---|
TarArchiveOutputStream | 归档*.tar 文件 |
TarArchiveInputStream | 解包*.tar 文件 |
ZipArchiveOutputStream | 归档压缩*.zip 文件 |
ZipArchiveInputStream | 解包解压*.zip 文件 |
JarArchiveOutputStream | 归档压缩*.jar 文件 |
JarArchiveInputStream | 解包解压*.jar 文件 |
DumpArchiveOutputStream | 归档*.dump 文件 |
DumpArchiveInputStream | 解包*.dump 文件 |
CpioArchiveOutputStream | 归档压缩*.cpio 文件 |
CpioArchiveInputStream | 解包解压*.cpio 文件 |
ArArchiveOutputStream | 归档压缩*.ar 文件 |
ArArchiveInputStream | 解包解压*.ar 文件 |
ArjArchiveInputStream | 解包解压*.arj 文件 |
SevenZOutputFile | 归档压缩*.7z 文件 |
SevenZFile | 解包解压*.7z 文件 |
其中zip,jar,cpio,ar,7z既支持归档也支持压缩,能在归档的过程中做压缩处理。
由于他们会处理一个个零散的文件,所以会有ArchiveEntry的概念,即一个ArchiveEntry代表归档包内的一个目录或文件。
tar
tar是Unix和Linux系统上的常用的压缩归档工具,可以将多个文件合并为一个文件,打包后的文件后缀亦为”tar”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public void tar() throws IOException { File srcDir = new File("/test"); String targetFile = "/test.tar"; try (TarArchiveOutputStream tos = new TarArchiveOutputStream( new FileOutputStream(targetFile))) { tarRecursive(tos, srcDir, ""); } }
private void tarRecursive(TarArchiveOutputStream tos, File srcFile, String basePath) throws IOException { if (srcFile.isDirectory()) { File[] files = srcFile.listFiles(); String nextBasePath = basePath + srcFile.getName() + "/"; if (ArrayUtils.isEmpty(files)) { TarArchiveEntry entry = new TarArchiveEntry(srcFile, nextBasePath); tos.putArchiveEntry(entry); tos.closeArchiveEntry(); } else { for (File file : files) { tarRecursive(tos, file, nextBasePath); } } } else { TarArchiveEntry entry = new TarArchiveEntry(srcFile, basePath + srcFile.getName()); tos.putArchiveEntry(entry); FileUtils.copyFile(srcFile, tos); tos.closeArchiveEntry(); } }
public void untar() throws IOException { InputStream is = new FileInputStream("/test.tar"); String outPath = "/test"; try (TarArchiveInputStream tis = new TarArchiveInputStream(is)) { TarArchiveEntry nextEntry; while ((nextEntry = tis.getNextTarEntry()) != null) { String name = nextEntry.getName(); File file = new File(outPath, name); if (nextEntry.isDirectory()) { file.mkdir(); } else { FileUtils.copyToFile(tis, file); file.setLastModified(nextEntry.getLastModifiedDate().getTime()); } } } }
|
7z
7z 是一种全新的压缩格式,它拥有极高的压缩比。
7z 格式的主要特征:
- 开放的结构
- 高压缩比
- 强大的 AES-256 加密
- 能够兼容任意压缩、转换、加密算法
- 最高支持 16000000000 GB 的文件压缩
- 以 Unicode 为标准的文件名
- 支持固实压缩
- 支持文件头压缩
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public void _7z() throws IOException { try (SevenZOutputFile outputFile = new SevenZOutputFile(new File("/test.7z"))) { File srcFile = new File("/test"); _7zRecursive(outputFile, srcFile, ""); } }
private void _7zRecursive(SevenZOutputFile _7zFile, File srcFile, String basePath) throws IOException { if (srcFile.isDirectory()) { File[] files = srcFile.listFiles(); String nextBasePath = basePath + srcFile.getName() + "/"; if (ArrayUtils.isEmpty(files)) { SevenZArchiveEntry entry = _7zFile.createArchiveEntry(srcFile, nextBasePath); _7zFile.putArchiveEntry(entry); _7zFile.closeArchiveEntry(); } else { for (File file : files) { _7zRecursive(_7zFile, file, nextBasePath); } } } else { SevenZArchiveEntry entry = _7zFile.createArchiveEntry(srcFile, basePath + srcFile.getName()); _7zFile.putArchiveEntry(entry); byte[] bs = FileUtils.readFileToByteArray(srcFile); _7zFile.write(bs); _7zFile.closeArchiveEntry(); } } public void un7z() throws IOException { String outPath = "/test"; try (SevenZFile archive = new SevenZFile(new File("test.7z"))) { SevenZArchiveEntry entry; while ((entry = archive.getNextEntry()) != null) { File file = new File(outPath, entry.getName()); if (entry.isDirectory()) { file.mkdirs(); } if (entry.hasStream()) { final byte [] buf = new byte [1024]; final ByteArrayOutputStream baos = new ByteArrayOutputStream(); for (int len = 0; (len = archive.read(buf)) > 0;) { baos.write(buf, 0, len); } FileUtils.writeByteArrayToFile(file, baos.toByteArray()); } } } }
|
修改归档文件
有时候我们会有修改归档内文件的需求,比如添加、删除一个文件,修改其中的文件内容等,当然我们也可以全部解压出来改完后在压缩回去。这样除了代码量多一些外,归档文件大也会导致操作时间过长。那么有没有办法用代码去动态的修改归档文件里的内容呢?
org.apache.commons.compress.changes包下正好就提供了一些类用于动态的修改归档文件里的内容。下面看一个简单的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| String tarFile = "/test.tar"; InputStream is = new FileInputStream(tarFile);
OutputStream os = new FileOutputStream(tarFile); try (TarArchiveInputStream tais = new TarArchiveInputStream(is); TarArchiveOutputStream taos = new TarArchiveOutputStream(os)) { ChangeSet changes = new ChangeSet(); changes.delete("dir/1.txt"); changes.delete("t"); File addFile = new File("/a.txt"); ArchiveEntry addEntry = taos.createArchiveEntry(addFile, addFile.getName()); changes.add(addEntry, new FileInputStream(addFile)); ChangeSetPerformer performer = new ChangeSetPerformer(changes); ChangeSetResults result = performer.perform(tais, taos); }
|
其他
简单工厂
commons-compress还提供了一些简单的工厂类用户动态的获取压缩流和归档流。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ArchiveStreamFactory factory = new ArchiveStreamFactory(); String archiveName = ArchiveStreamFactory.TAR; InputStream is = new FileInputStream("/in.tar"); OutputStream os = new FileOutputStream("/out.tar");
ArchiveInputStream ais = factory.createArchiveInputStream(archiveName, is); ArchiveOutputStream aos = factory.createArchiveOutputStream(archiveName, os);
CompressorStreamFactory factory = new CompressorStreamFactory(); String compressName = CompressorStreamFactory.GZIP; InputStream is = new FileInputStream("/in.gz"); OutputStream os = new FileOutputStream("/out.gz");
CompressorInputStream cis = factory.createCompressorInputStream(compressName, is); CompressorOutputStream cos = factory.createCompressorOutputStream(compressName, os);
|
同时解压解包
上面说了很多都是单一的操作,那么如果解压”test.tar.gz”这种归档和压缩于一体的文件呢?
其实很简单,我们不需要先解压在解包,可以一步同时完成解压和解包,只需要将对应的流包装一下即可(不得不感叹Java IO的装饰者模式设计真的很巧妙)。下面看代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| String outPath = "/test"; InputStream is = new FileInputStream("/test.tar.gz");
CompressorInputStream gis = new GzipCompressorInputStream(is);
try (ArchiveInputStream tgis = new TarArchiveInputStream(gis)) { ArchiveEntry nextEntry; while ((nextEntry = tgis.getNextEntry()) != null) { String name = nextEntry.getName(); File file = new File(outPath, name); if (nextEntry.isDirectory()) { file.mkdir(); } else { FileUtils.copyToFile(tgis, file); file.setLastModified(nextEntry.getLastModifiedDate().getTime()); } } }
|
Commons Configuration
是一个Java应用程序的配置管理工具,可以从properties或者xml文件中加载配置信息。
Commons CSV
是一个用来读写各种Comma Separated Value(CSV)格式文件的Java类库。
Commons Daemon
实现将普通的Java应用变成系统的后台服务,例如 Tomcat 就是利用这个项目来实现作为 Linux 和 Windows 的服务启动和停止的。
Commons DBCP
数据库连接池。
Commons DBUtils
是JDBC工具组件,对传统操作数据库的类进行二次封装,可以把结果集转化成List。
Commons Digester
是XML到Java对象的映射工具集。
Commons Email
是邮件操作组件,对Java Mail API进行了封装,提供了常用的邮件发送和接收类,简化邮件操作。该组件依赖Java Mail API。
Commons Exec
提供一些常用的方法用来执行外部进程,如执行exe文件或命令行。
Commons FileUpload
为Web应用程序或Servlet提供文件上传功能,Struts2和SpringMVC的文件上传组件。
Commons IO
是处理IO的工具类包,对java.io进行扩展,提供了更加方便的IO操作。
Commons JCI
提供通用的Java编译器接口。
Commons Lang3
是处理Java基本对象方法的工具类包,该类包提供对字符、数组等基本对象的操作,弥补了java.lang api基本处理方法上的不足。
工具类 | 简介 |
---|
ArrayUtils | 用于对数组的操作,如添加、查找、删除、子数组、倒序、元素类型转换等 |
BitField | 用于操作位元,提供了一些方便而安全的方法 |
BooleanUtils | 用于操作和转换boolean或者Boolean及相应的数组 |
CharEncoding | 包含了Java环境支持的字符编码,提供是否支持某种编码的判断 |
CharRange | 用于设定字符范围并做相应检查 |
CharSet | 用于设定一组字符作为范围并做相应检查 |
CharSetUtils | 用于操作CharSet |
CharUtils | 用于操作char值和Character对象 |
ClassUtils | 用于对Java类的操作,不使用反射 |
ObjectUtils | 用于操作Java对象,提供null安全的访问和其他一些功能 |
RandomStringUtils | 用于生成随机的字符串 |
SerializationUtils | 用于处理对象序列化,提供比一般Java序列化更高级的处理能力 |
StringEscapeUtils | 用于正确处理转义字符,产生正确的Java、JavaScript、HTML、XML和SQL代码 |
StringUtils | 处理String的核心类,提供了相当多的功能 |
SystemUtils | 在java.lang.System基础上提供更方便的访问,如用户路径、Java版本、时区、操作系统等判断 |
Validate | 提供验证的操作,有点类似assert断言 |
WordUtils | 用于处理单词大小写、换行等 |
Commons Logging
提供统一的日志接口,同时兼顾轻量级和不依赖于具体的实现。类包给中间件/日志工具开发者一个简单的日志操作抽象,允许程序开发人员使用不同的具体日志实现工具。
Commons Math
轻量级自容器的数学和统计计算方法类包,包含大多数常用的数值算法。
Commons Net
封装了各种网络协议的客户端,支持FTP、NNTP、SMTP、POP3、Telnet等协议。
Commons Pool
提供了一整套用于实现对象池化的框架,以及若干各具特色的对象池实现,可以有效地减少处理对象池化时的工作量。类包用于提高像文件句柄、数据库连接、socket通信这类大对象的调用效率,简单的说就是一种对象一次创建多次使用的技术。
Commons Primitives
提供了一个更小,更快和更易使用的对Java基本类型的支持。
Commons Validator
提供了一个简单的、可扩展的框架来在一个XML文件中定义校验器(校验方法)和校验规则。支持校验规则的和错误消息的国际化。
Apache HttpClient
曾经是Apache Commons的子项目,后来独立出来。HttpClient简化HTTP客户端与服务器的各种通讯,实现HTTP客户端程序(也就是浏览器程序)的功能。