介紹
ota差分算法,常見的有bsdiff,hdiffpatch,xdelta3這三種,主要是解決ota升級中升級包更新推送升級包不必全量推送的問題。比如,一個舊的升級包100M,新的升級包110M,通過差分算法工具云端可以把兩個包之間有差異的地方抽離出來新生成一個比較小的差分包,云端只要向客戶端推送這個比較小的差分包,客戶端拿到差分包之后,再通過差分算法工具利用舊包和拿到的差分包還原成新的升級包實現(xiàn)升級包的替換安裝。這三種差分算法都可以完成這個步驟,其中hdiffpatch是性能比較好、占用內(nèi)存比較少的方案。
HDiffPatch安裝
github地址:https://hub.fastgit.org/sisong/HDiffPatch
安裝包下載地址:https://hub.fastgit.org/sisong/HDiffPatch/releases/tag/v4.1.2
截止發(fā)文最新版本是v4.1.2,下載對應(yīng) hdiffpatch_v4.1.2_bin_linux64.zip即可。
解壓后按照github上readerme.md里描述的方法安裝并編譯即可:
cd <dir>/HDiffPatch
make LZMA=0 ZSTD=0 MD5=0
差分命令:hdiffz oldPath newPath outDiffFile (oldPath:舊升級包路徑,newPath:新升級包路徑,outDiffFile:將要生成的差分包文件路徑)
還原命令:hpatchz oldPath diffFile outNewPath(oldPath:舊升級包路徑,diffFile:差分包路徑,還原生成的升級包路徑)
演示
比如我的hdiffpatch安裝路徑為/home/zhaohy/hdiffpatch/HDiffPatch
在/home/zhaohy/hdiffpatch/test-20211116文件下有兩個文件分別是:10M_old.zip、10M_new.zip代表舊升級包和新升級包。
差分:
zhaohy@zhaohy-VirtualBox:~/hdiffpatch/HDiffPatch$ cd /home/zhaohy/hdiffpatch/HDiffPatch
zhaohy@zhaohy-VirtualBox:~/hdiffpatch/HDiffPatch$ ./hdiffz /home/zhaohy/hdiffpatch/test-20211116/10M_old.zip /home/zhaohy/hdiffpatch/test-20211116/10M_new.zip /home/zhaohy/hdiffpatch/test-20211116/10M_diff.zip
old : "/home/zhaohy/hdiffpatch/test-20211116/10M_old.zip"
new : "/home/zhaohy/hdiffpatch/test-20211116/10M_new.zip"
out : "/home/zhaohy/hdiffpatch/test-20211116/10M_diff.zip"
hdiffz run with compress plugin: ""
oldDataSize : 12382208
newDataSize : 11178603
diffDataSize: 231050
diff time: 1.821 s
out diff file ok!
load diffFile for test by patch:
diffDataSize: 231050
patch time: 0.003 s
patch check diff data ok!
all time: 1.825 s
可以看到生成差分包成功。
還原:
zhaohy@zhaohy-VirtualBox:~/hdiffpatch/HDiffPatch$ ./hpatchz /home/zhaohy/hdiffpatch/test-20211116/10M_old.zip /home/zhaohy/hdiffpatch/test-20211116/10M_diff.zip /home/zhaohy/hdiffpatch/test-20211116/10M_out_new.zip
old : "/home/zhaohy/hdiffpatch/test-20211116/10M_old.zip"
diff: "/home/zhaohy/hdiffpatch/test-20211116/10M_diff.zip"
out : "/home/zhaohy/hdiffpatch/test-20211116/10M_out_new.zip"
oldDataSize : 12382208
diffDataSize: 231050
newDataSize : 11178603
patch ok!
hpatchz time: 0.030 s
可以看到還原成功,比對10M_new.zip和10M_out_new.zip發(fā)現(xiàn)他們兩個是一樣的。
java調(diào)用動態(tài)庫libhdiffpatch.so
把hdiffpatch源文件編譯成so動態(tài)庫文件,編譯過程就不寫了(C++編譯我也不會),這里放一個大神編譯好的so文件下載地址吧:libhdiffpatch.so
把libhdiffpatch.so文件放在src/main/resource/linux-x86-64/文件夾下
gradle引入jna
compile "net.java.dev.jna:jna:5.7.0"
創(chuàng)建HDiff類
package hdiffpatch.core;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface HDiff extends Library{
HDiff INSTANCE = (HDiff) Native.load("hdiffpatch", HDiff.class);
//diff usage: hdiffz [options] oldPath newPath outDiffFile
void hdiffz(String oldData, String newData, String outPatchFile, long size);
}
創(chuàng)建HPatch類
package hdiffpatch.core;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface HPatch extends Library {
HPatch INSTANCE = (HPatch) Native.load("hdiffpatch", HPatch.class);
//patch usage: hpatchz [options] oldPath diffFile outNewPath
void hpatchz(String oldPath, String diffFile, String outNewPath);
}
創(chuàng)建調(diào)用類HdiffPatch
package hdiffpatch.core;
import java.io.FileNotFoundException;
import ly.mp.iov.bsdiff.util.FileUtils;
/**
* 二進制文件差分Java版
*/
public class HdiffPatch {
/**
* 差分
* @param oldFile 原始文件
* @param newFile 目標文件
* @param patchFile 差分文件
* @throws FileNotFoundException oldFile或newFile不存在
*/
public static void diff(String oldFile, String newFile, String patchFile) throws FileNotFoundException {
FileUtils.requireFileExist(oldFile);
FileUtils.requireFileExist(newFile);
HDiff.INSTANCE.hdiffz(oldFile,newFile, patchFile, 1024*1024*128);
}
/**
* 還原
* @param oldFile 原始文件地址
* @param diffPath 差分文件地址
* @param outNewPath 還原新生成文件地址
* @throws FileNotFoundException oldFile或patchFile不存在
*/
public static void patch(String oldPath, String diffPath, String outNewPath) throws FileNotFoundException {
FileUtils.requireFileExist(oldPath);
FileUtils.requireFileExist(diffPath);
HPatch.INSTANCE.hpatchz(oldPath, diffPath, outNewPath);
}
public static void main(String[] args) {
//System.out.println(System.getProperty("java.library.path"));
String path = "/home/zhaohy/hdiffpatch/test-20211116/";
String oldFile = path + "10M_old.zip";
String newFile = path + "10M_new.zip";
String patchFile = path + "10M_diff.zip";
String outNewPath = path + "10M_out_new.zip";
try {
HdiffPatch.diff(oldFile, newFile, patchFile);//差分
HdiffPatch.patch(oldFile, patchFile, outNewPath);//還原
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println(patchFile);
}
}
貼上FileUtils類:
package hdiffpatch.util;
import java.io.File;
import java.io.FileNotFoundException;
/**
* 文件工具類
*/
public class FileUtils {
/**
* 校驗文件是否存在,如果不存在則拋出異常
* @param filePath 文件路徑
* @throws FileNotFoundException 文件不存在
*/
public static void requireFileExist(String filePath) throws FileNotFoundException {
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException(filePath);
}
}
}
如此運行main方法也是可以正常差分和還原包的。完結(jié)散花~