commons-codec 编解码库
commons-codec这个库主要实现了文本和二进制数据之间的各种编码算法,常用的包括Base64编解码,MD、SHA系列散列摘要算法,HMAC散列消息认证算法,URL编码等。
引入Maven依赖
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
Base64编解码
下面代码将一个文本字符串进行Base64编码和解码。
Base64 base64 = new Base64();
//base64编码
String strBase64 = base64.encodeToString(str.getBytes("UTF-8"));
//base64解码
str = new String(base64.decode(strBase64), "UTF-8");
对于图片或是其它的二进制数据也是同样的道理,下面是Base64编解码图片的例子。
import org.apache.commons.codec.binary.Base64;
import java.io.*;
public class Main
{
public static void main(String[] args) throws Exception
{
//读取图片二进制数据,存入byte[]
InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("1.png");
byte[] buffer = new byte[1024];
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int len;
while ((len = inputStream.read(buffer)) != -1)
{
byteArrayOutputStream.write(buffer, 0, len);
}
byte[] imageBytes = byteArrayOutputStream.toByteArray();
inputStream.close();
byteArrayOutputStream.close();
Base64 base64 = new Base64();
//base64编码
String imageBase64Str = base64.encodeToString(imageBytes);
//base64解码
imageBytes = base64.decode(imageBase64Str);
//将解码后的二进制数据再写入文件
File newImageFile = new File("/home/gacfox/2.png");
OutputStream outputStream = new FileOutputStream(newImageFile);
outputStream.write(imageBytes);
outputStream.close();
System.out.println(imageBase64Str);
}
}
实际上Base64编解码的API和上面处理文本时是一样的。
注意:
1.如果需要在HTML中直接使用Base64显示图片,把上面生成的base64编码直接写进<img src=""是无效的,必须在base64编码前加上头信息data:image/png;base64,,注明图片格式是PNG,使用的编码是Base64,而解码时一定要记得去掉头信息,对于JPG等其它格式也是类似的。
2.关于图片格式,假如我们读取的图片是JPG格式,Base64编码的仅仅是JPG格式的二进制数据,而不是位图数据,这里不要弄混了。无论是在网页上显示Base64编码的图片,还是在诸如JavaFX的ImageView控件里显示某段二进制数据,JPG格式的二进制数据与位图二进制数据之间转换都是由浏览器或是ImageView底层实现的,跟我们的Java程序没关系。
散列摘要算法
commons-codec支持MD5、SHA系列等常见的散列摘要算法。
下面例子是使用SHA256对一个字符串进行散列值计算。commons-codec中,对于SHA256算法,提供了sha256()和sha256Hex()两个函数,区别就是后者返回的是:算法获得的散列值二进制数据取每四位为一个十六进制字符连接而成的字符串。实际上散列算法返回的是二进制数据,但我们一般使用的都是这种处理后的字符串,因此这个函数十分方便。
String str = "你好,世界!";
String sha256Str = DigestUtils.sha256Hex(str);
对于计算较大文件的散列值,把文件全读入内存肯定是不可取的,commons-codec提供了方便的函数对文件输入流进行处理。
InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("1.png");
String fileSha256 = DigestUtils.sha256Hex(inputStream);
URL编解码
下面例子是对字符串进行URL编码和解码操作。
URLCodec urlCodec = new URLCodec();
String encodedStr = urlCodec.encode(str);
String decodedStr = urlCodec.decode(encodedStr);
坑点注意:JDK和commons-codec中的URL编码都有一个相同的坑。编码时,空格会被编码为+(而非%20),+会被编码为%2B;解码时,+和%20都会被解码为空格,而%2B会被解码为+,这和浏览器的encodeURIComponent()函数的行为是不同的,不仔细处理的话会造成很多Bug。
查阅资料后得知,Java遵循的RFC规范和浏览器中实际使用规范在使用场景上有些区别,其中有一些历史遗留问题造成了这两种规范的不一致,一个比较简单的解决方法是编码后将+替换为%20。
String s = "Hello world";
String sEncoded = urlCodec.encode(s);
sEncoded = sEncoded.replaceAll("\\+", "%20");
String sDecoded = urlCodec.decode(sEncoded);
System.out.println(sEncoded);
System.out.println(sDecoded);
上面这样替换一下后,行为就和浏览器基本一致了。