背景:这个主要是需要动态更新Android系统的开机动画。
bootanimation.zip不是压缩形式的,而是归档形式的zip包。
java zip包可以支持STORE(归档)方式,但是查到的代码基本都有问题,都没有达到我想要归档效果。现记录下解决之后的code,避免有相同需求的同学再次踩坑。
目录结构:
两个分别有png图片的文件夹和一个txt文本。
private void CreateZipFile(){
String zipPath = "data/local/my.zip";
File zipFile = new File(zipPath);
if(zipFile.exists())
zipFile.delete();
//创建zip包
try{
ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(zipPath));
ZipOneItem(zip,new File("data/local/part0"),"");
ZipOneItem(zip,new File("data/local/part1"),"");
ZipOneItem(zip,new File("data/local/3.txt"),"");
zip.close();
Log.d(TAG, "CreateZipFile SUCCESS!!!");
}catch(FileNotFoundException ex){
Log.d(TAG, "CreateZipFile FileNotFoundException!!!");
ex.printStackTrace();
}catch(IOException e){
Log.d(TAG, "CreateZipFile IOException!!!");
e.printStackTrace();
}
}
//压缩一个文件或者目录
private void ZipOneItem(ZipOutputStream zip, File f,String base){
zip.setMethod(ZipOutputStream.STORED);//这个其实可有可无,ZipOutputStream.STORED其实就是后边的ZipEntry.STORED
Log.d(TAG, "ZipOneItem in,f="+f.getName()+",base="+base);
try{
if(f.isDirectory()){
File[] files = f.listFiles();
//如果是多级目录part0/0.png这种,zip会根据/前边的名字自行构建多级目录的,所以这里只考虑空文件的情况,多级目录在下边else部分基本就可以。
if(files.length == 0){ //构造一个空文件夹
ZipEntry entry = new ZipEntry(base);
zip.putNextEntry(entry);
}
//多级目录情况这里可能有点问题,读者请自行修改赋值路径相关。
base = base.length() == 0 ? f.getName() + "/" : base + "/";
for(int i=0; i < files.length; i++){
ZipOneItem(zip,files[i],base + files[i].getName());
}
}else{
//创建一个压缩文件
base = base.length() == 0 ? f.getName() : base;//如果只压缩一个文件,还是要给个文件名才行
Log.d(TAG, "ZipOneItem base="+base);
ZipEntry entry = new ZipEntry(base);
//这里开始很重要
entry.setMethod(ZipEntry.STORED);
entry.setCompressedSize(f.length());
entry.setSize(f.length());
CRC32 crc = new CRC32();
crc.update(getFileBytes(f));
entry.setCrc(crc.getValue());
//以上很重要
zip.putNextEntry(entry);
int bufferLen = 1024;
int fLen = (int)f.length();
if(fLen < bufferLen){ //因为是储存,所以文件大小不能变。当小于1024时,使用文本大小
bufferLen = fLen;
}
byte[] buffer = new byte[bufferLen];
FileInputStream fis = new FileInputStream(f);
int size = 0;
while( (size = fis.read(buffer)) != -1){
zip.write(buffer,0,size);//这个很重要。之前查到的基本都是zip.write(buffer),这个会报错CRC missmatch。大坑。。。
}
//zip.closeEntry();这个可以不要,下一次的putNextEntry或者上边的zip.close都会调用closeEntry()
fis.close();
}
}catch(Exception e){
e.printStackTrace();
Log.d(TAG, "ZipOneItem ERROR");
}
Log.d(TAG, "ZipOneItem SUCCESS");
}
private static byte[] getFileBytes(File file) throws Exception {
byte[] buffer;
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
bos.close();
buffer = bos.toByteArray();
return buffer;
}
这个功能只适用于我个人,其他功能只能作为参考,请慎用。