写这篇技术文章的初衷,是因为工作需要将巨大base64字符串解码为二进制文件,在百度和google了一番后,发现网上根本没有现成的解决方案,大部分文章都是复制粘贴的。
说实话,首次看到这个问题,大部分人都会疑惑,到底是什么样的应用场景会用base64编码来处理大文件,这岂不自寻烦恼吗?其实很多场景都会遇到大文件的Base64解码问题,例如安卓中的webview处理blob文件下载的时候,如果遇到较大的文件(100M以上),需要将超大Base64文本解析为二进制文件。
先来分析下这个问题的原因,一般搞开发的都知道base64编码很大程度上是简化了我们传输文件的方式,特别是对于没有文件系统的团队来说,更是难得,但是这里的文件仅仅指的是小文件、小图片(如:头像、二维码等)之类的,因为大文件转化出来的base64编码真的很长很长,先说这不利于网络传输,就算勉强传输过去了,数据库也不见得能存储下来,就算勉强存储下来了,重新再获取的时候也一定会影响速度和效率。
base64编码出来的长度实际上是没有大小限制的,因为base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
解决方法
按照上述对base64的分析,只需要将超大字符串按照4的倍数进行截取后,再进行解码,然后通过FileOutputStream输出流,依次将字节数组写入文件即可。下面是实现的代码,解码效率也是比较高的。另外,如果您需要参考其他的应用是如何实现某些功能的逻辑代码,可以通过百度搜索 安卓修改大师 来将apk文件直接转换为可编译可打包的android studio源代码,本解决方案就是参考了 装酷神器 的源代码来实现的。
public static void DecodeHugeBase64ToFile(String fileContent, String outputFile) {
File myCaptureFile = null;
FileOutputStream fos= null;
try {
myCaptureFile = new File(outputFile);
if (!myCaptureFile.exists()) {
myCaptureFile.createNewFile();
}
String filepath = myCaptureFile.getAbsolutePath();
File file = new File(filepath);
if (file.exists()) {
file.delete();
}
fos = new FileOutputStream(file);
int len = 500 * 1024;// * 1024; 这里调整每次解码的文本大小
int txtLen = fileContent.length();
int pages = (int) Math.ceil((double) txtLen / (double) len);
for (int i = 0; i < pages; i++) {
int lastPos = (i + 1) * len;
if (lastPos > txtLen) lastPos = txtLen;
String temp = fileContent.substring(i * len, lastPos);
byte[] respBytes = Base64.decode(temp, Base64.DEFAULT);
fos.write(respBytes);
}
fos.flush();
} catch (IOException e) {
e.printStackTrace();
}
finally {
if(fos!=null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}