logo
0
0
WeChat Login
sisong<sisong@gmail.com>
update version;

release license PRs Welcome +issue Welcome
release Build Status Build status
中文版 | english

HDiffPatch 是一个C\C++库和命令行工具,用于在二进制文件或文件夹之间执行 diff(创建补丁) 和 patch(打补丁);跨平台、运行速度快、创建的补丁小、支持巨大的文件并且diff和patch时都可以控制内存占用量。

HDiffPatch 定义了自己的补丁包格式,同时这个库也完全兼容了 bsdiff4endsley/bsdiff 的补丁包格式,并部分兼容open-vcdiffxdelta3 的补丁包格式 VCDIFF(RFC 3284)

如果你需要在嵌入式系统(MCU、NB-IoT)等设备上进行增量更新(OTA), 可以看看例子 HPatchLite, +tinyuz 解压缩器可以在1KB内存的设备上运行! HPatchLite也支持一种简单的原地更新(inplace-patch)实现,用以支持存储受限的设备。

需要更新你自己的安卓apk? 需要对Jar或Zip文件执行 diff 和 patch ? 可以试试 ApkDiffPatch, 可以创建更小的补丁! 注意: ApkDiffPath 不能被安卓应用商店作为增量更新所用,因为该算法要求在diff前对apk文件进行重新签名。

sfpatcher 不要求对apk文件进行重新签名 (类似 archive-patcher),是为安卓应用商店专门设计优化的算法,可以针对apk创建更小的补丁,patch速度是 archive-patcher 的xx倍,并且只需要O(1)内存。

如果你没有旧版本的数据(或者旧版本非常多或者被修改),因此不能提前创建好补丁包。 那你可以看看使用同步算法来进行增量更新的例子 hsynz (类似 zsync),新版本只需要发布处理一次, 然后旧版本数据的拥有者们可以根据获得的新版本的信息自己执行diff和patch。 hsynz 支持 zstd 压缩算法并且比 zsync 速度快得多;而且可以兼容 zsync 的文件格式。
另外,如果你本地有新版本数据而没有旧版本的数据,但可以拿到旧版本数据的hash证书文件(.hsyni), 那也可以创建出一个 hpatchz 格式的补丁(使用场景类似 rsync);见 hsynz 中的 demo 命令行程序 hsign_diff

注意: 本库不处理文件元数据,如文件最后写入时间、权限、链接文件等。对于这个库,文件就像一个字节流;如果需要您可以扩展此库或使用其他工具。


二进制发布包

从 release 下载 : 命令行程序分别运行在 Windows、Linux、MacOS操作系统。 .so库文件用于安卓。
用命令行创建一个补丁:
$hdiffz -m-6 -SD -c-zstd-21-24 -d oldPath newPath outDiffFile
如果文件非常大,可以试试将 -m-6 改为 -s-64
打补丁:
$hpatchz oldPath diffFile outNewPath

自己编译

$ cd <dir>/HDiffPatch

Linux or MacOS X

试试:
$ make LDEF=0 LZMA=0 ZSTD=0 MD5=0 XXH=0
bzip2 : 如果编译失败,显示 fatal error: bzlib.h: No such file or directory,请使用系统的包管理器安装libbz2,然后再试一次;或者下载并使用libbz2源代码来编译:

$ git clone https://github.com/sisong/bzip2.git ../bzip2 $ make LDEF=0 LZMA=0 ZSTD=0 MD5=0 XXH=0 BZIP2=1

如果需要支持 lzma、zstd 和 md5 xxh 等 默认编译设置,试试:

$ git clone https://github.com/sisong/libmd5.git ../libmd5 $ git clone https://github.com/sisong/xxHash.git ../xxHash $ git clone https://github.com/sisong/lzma.git ../lzma $ git clone https://github.com/sisong/zstd.git ../zstd $ git clone https://github.com/sisong/zlib.git ../zlib $ git clone https://github.com/sisong/libdeflate.git ../libdeflate $ make

提示:你可以使用 $ make -j 来并行编译。

Windows

使用 Visual Studio 打开 builds/vc/HDiffPatch.sln 来编译之前,先将第三方库下载到同级文件夹中,如下所示:

$ git clone https://github.com/sisong/libmd5.git ../libmd5 $ git clone https://github.com/sisong/xxHash.git ../xxHash $ git clone https://github.com/sisong/lzma.git ../lzma $ git clone https://github.com/sisong/zstd.git ../zstd $ git clone https://github.com/sisong/zlib.git ../zlib $ git clone https://github.com/sisong/libdeflate.git ../libdeflate $ git clone https://github.com/sisong/bzip2.git ../bzip2

libhpatchz.so for Android

  • 安装 Android NDK
  • $ cd <dir>/HDiffPatch/builds/android_ndk_jni_mk
  • $ build_libs.sh (或者 Windows下执行 $ build_libs.bat, 就可以得到 *.so 安卓库了)
  • 在你的安卓项目中添加 com/github/sisong/HPatch.java (所在路径 HDiffPatch/builds/android_ndk_jni_mk/java/) 和 .so 文件, java 代码就可以调用 libhpatchz.so 中的 patch 函数了。

diff 命令行用法和参数说明:

创建新旧版本间的补丁: hdiffz [options] oldPath newPath outDiffFile
压缩一个文件或文件夹: hdiffz [-c-...] "" newPath outDiffFile
测试补丁是否正确: hdiffz -t oldPath newPath testDiffFile
补丁使用新的压缩插件另存: hdiffz [-c-...] diffFile outDiffFile
显示补丁的信息: hdiffz -info diffFile
创建该版本的校验清单: hdiffz [-g#...] [-C-checksumType] inputPath -M#outManifestTxtFile
校验输入数据后创建补丁: hdiffz [options] -M-old#oldManifestFile -M-new#newManifestFile oldPath newPath outDiffFile

oldPath、newPath、inputPath 可以是文件或文件夹, oldPath可以为空, 输入参数为 "" 选项: -m[-matchScore] 默认选项; 所有文件都会被加载到内存; 一般生成的补丁文件比较小; 需要的内存大小:(新版本文件大小+ 旧版本文件大小*5(或*9 当旧版本文件大小>=2GB时))+O(1); 匹配分数matchScore>=0,默认为6,二进制数据时推荐设置为0到4,文件数据时推荐4--9等,跟输入 数据的可压缩性相关,一般输入数据的可压缩性越大,这个值就可以越大。 -s[-matchBlockSize] 所有文件当作文件流加载;一般速度比较快; 需要的内存大小: O(旧版本文件大小*16/matchBlockSize+matchBlockSize*5*parallelThreadNumber); 匹配块大小matchBlockSize>=4, 默认为64, 推荐16,32,48,1k,64k,1m等; 一般匹配块越大,内存占用越小,速度越快,但补丁包可能变大。 -block-fastMatchBlockSize 必须和-m配合使用; 在使用较慢的逐字节匹配之前使用基于块的快速匹配, 默认-block-1k; 如果设置为-block-0,意思是关闭基于块的提前匹配; 快速块匹配大小fastMatchBlockSize>=4, 推荐128,4k,64k等; 如果新版本和旧版本相同数据比较多,那diff速度就会比较快,并且减少内存占用, 但有很小的可能补丁包会稍微变大。 -cache 必须和-m配合使用; 给较慢的匹配开启一个大型缓冲区,来加快匹配速度(不影响补丁大小), 默认不开启; 如果新版本和旧版本不相同数据比较多,那diff速度就会比较快; 该大型缓冲区最大占用O(旧版本文件大小)的内存, 并且需要较多的时间来创建(从而可能降低diff速度)。 -SD[-stepSize] 创建单压缩流的补丁文件, 这样patch时就只需要一个解压缩缓冲区, 并且可以支持边下载边patch, 并支持多线程patch; 压缩步长stepSize>=(1024*4), 默认为256k, 推荐64k,2m等。 -BSD 创建一个和bsdiff4兼容的补丁, 不支持参数为文件夹。 也支持和-SD选项一起运行(不使用其stepSize), 从而创建单压缩流的补丁文件, 兼容endsley/bsdiff格式 (https://github.com/mendsley/bsdiff)。 -VCD[-compressLevel[-dictSize]] 创建一个标准规范VCDIFF格式的补丁, 不支持参数为文件夹。 默认输出补丁不带压缩, 格式和 $open-vcdiff ... 或 $xdelta3 -S -e -n ... 命令输出的补丁格式兼容; 如果设置了压缩级别compressLevel, 那输出格式和 $xdelta3 -S lzma -e -n ...命令输出的补丁格式兼容; 压缩输出时补丁文件使用7zXZ(xz)算法压缩, compressLevel可以选择0到9, 默认级别7; 压缩字典大小dictSize可以设置为 4096, 4k, 4m, 16m等, 默认为8m 支持多线程并行压缩。 注意: 输出的补丁的格式中可能使用了巨大的源窗口大小! -p-parallelThreadNumber 设置线程数parallelThreadNumber>1时,开启多线程并行模式; 默认为4;需要占用较多的内存。 -p-search-searchThreadNumber 默认情况下搜索线程数searchThreadNumber的值和parallelThreadNumber相同; 旧文件在HDD硬盘上时的警告:在使用-s-matchBlockSize 或 -block-fastMatchBlockSize(和-m配合时)时, 多线程搜索需要频繁的随机磁盘读取,这可能会导致速度变慢;这时就需要关闭(searchThreadNumber<=1)多 线程搜索模式或者降低搜索线程数searchThreadNumber的值! -c-compressType[-compressLevel] 设置补丁数据使用的压缩算法和压缩级别等, 默认不压缩; 补丁另存时,使用新的压缩参数设置来输出新补丁; 支持的压缩算法、压缩级别和字典大小等: -c-zlib[-{1..9}[-dictBits]] 默认级别 9 压缩字典比特数dictBits可以为9到15, 默认为15。 支持多线程并行压缩,很快! -c-ldef[-{1..12}] 默认级别 12 输出压缩数据格式兼容于-c-zlib, 但比zlib压缩得更快或压缩得更小; 使用了libdeflate压缩算法,且压缩字典比特数dictBits始终为15。 支持多线程并行压缩,很快! -c-bzip2[-{1..9}] (或 -bz2) 默认级别 9 -c-pbzip2[-{1..9}] (或 -pbz2) 默认级别 8 支持并行压缩,生成的补丁和-c-bzip2的输出格式稍有不同。 -c-lzma[-{0..9}[-dictSize]] 默认级别 7 压缩字典大小dictSize可以设置为 4096, 4k, 4m, 128m等, 默认为8m 支持2个线程并行压缩。 -c-lzma2[-{0..9}[-dictSize]] 默认级别 7 压缩字典大小dictSize可以设置为 4096, 4k, 4m, 128m等, 默认为8m 支持多线程并行压缩,很快。 警告: lzma和lzma2是不同的压缩编码格式。 -c-zstd[-{0..22}[-dictBits]] 默认级别 20 压缩字典比特数dictBits 可以为10到30, 默认为23。 支持多线程并行压缩,较快(但内存占用会比较大)。 -C-checksumType 为文件夹间diff设置数据校验算法, 默认为fadler64; 支持的校验选项: -C-no 不校验 -C-crc32 -C-fadler64 默认 -C-md5 -C-xxh3 (需要 v4.12版本 patch端) -C-xxh128 推荐 (需要 v4.12版本 patch端) -n-maxOpenFileNumber 为文件夹间的-s模式diff设置最大允许同时打开的文件数; maxOpenFileNumber>=16, 默认为48; 合适的限制值可能不同系统下不同。 -g#ignorePath[#ignorePath#...] 为文件夹间的diff设置忽略路径(路径可能是文件或文件夹); 忽略路径列表的格式如下: #.DS_Store#desktop.ini#*thumbs*.db#.git*#.svn/#cache_*/00*11/*.tmp # 意味着路径名称之间的间隔; (如果名称中有“#”号, 需要改写为“#:” ) * 意味着匹配名称中的任意一段字符; (如果名称中有“*”号, 需要改写为“*:” ) / 如果该符号放在名称末尾,意味着必须匹配文件夹; -g-old#ignorePath[#ignorePath#...] 为文件夹间的diff设置忽略旧版本的路径; 如果旧版本中的某个文件数据可以被运行中的程序改动,那可以将该文件放到该忽略列表中; -g-new#ignorePath[#ignorePath#...] 为文件夹间的diff设置忽略新版本的路径; 一般情况下,该列表应该是空的吧? -M#outManifestTxtFile 创建inputPath的校验清单文件; 该输出文件是一个文本文件, 保存着inputPath中所有 文件和文件夹的信息; 该文件被用于manifest diff, 支持diff之前重新校验数据的正确性; 可用于确定历史版本的数据没有被篡改! -M-old#oldManifestFile 设置oldPath的清单文件oldManifestFile; 如果没有oldPath,那就不需要设置-M-old; -M-new#newManifestFile 设置newPath的清单文件newManifestFile; -D 强制执行文件夹间的diff, 即使输入的是2个文件; 从而为文件间的补丁添加校验功能。 默认情况下oldPath或newPath有一个是文件夹时才会执行文件夹间的diff。 -neq 打开检查: 如果newPath和oldPath的数据都相同,则返回错误; 默认不执行该相等检查。 -d 只执行diff, 不要执行patch检查, 默认会执行patch检查. -t 只执行patch检查, 检查是否 patch(oldPath,testDiffFile)==newPath ? -f 强制文件写覆盖, 忽略输出的路径是否已经存在; 默认不执行覆盖, 如果输出路径已经存在, 直接返回错误; 如果设置了-f,但路径已经存在并且是一个文件夹, 那么会始终返回错误。 --patch 切换到 hpatchz 模式; 可以支持hpatchz命令行的相关参数和功能。 -info 显示补丁的信息。 -v 输出程序版本信息。 -h 或 -? 输出命令行帮助信息 (该说明)。

patch 命令行用法和参数说明:

打补丁: hpatchz [options] oldPath diffFile outNewPath
解压缩一个文件或文件夹: hpatchz [options] "" diffFile outNewPath
显示补丁的信息: hpatchz -info diffFile
创建一个自释放包: hpatchz [-X-exe#selfExecuteFile] diffFile -X#outSelfExtractArchive
(将目标平台的hpatchz可执行文件和补丁包文件合并成一个可执行文件, 称作自释放包SFX)
执行一个自释放包: selfExtractArchive [options] oldPath -X outNewPath
(利用自释放包来打补丁,将包中自带的补丁数据应用到oldPath上, 合成outNewPath)
执行一个自解压包: selfExtractArchive (等价于:$selfExtractArchive -f {""|"."} -X "./")

oldPath可以为空, 输入参数为 "" 选项: -s[-cacheSize] 默认选项,并且默认设置为-s-8m; oldPath所有文件被当作文件流来加载; cacheSize可以设置为262144 或 256k, 64m, 512m 等 需要的内存大小: (cacheSize + 4*解压缩缓冲区)+O(1) 而如果diffFile是单压缩流的补丁文件(用hdiffz -SD-stepSize所创建) 那需要的内存大小: (cacheSize+ stepSize + 1*解压缩缓冲区)+O(1); 如果diffFile是用hdiffz -BSD、bsdiff4、hdiffz -VCD、xdelta3、open-vcdiff所创建 那需要的内存大小: (cacheSize + 3*解压缩缓冲区); 如果diffFile是VCDIFF格式补丁文件: 如果是用hdiffz -VCD创建,那推荐用-s模式; 如果是xdelta、open-vcdiff所创建,那推荐用-m模式。 -m oldPath所有文件数据被加载到内存中; 需要的内存大小: (oldFileSize + 4*解压缩缓冲区)+O(1) 而如果diffFile是单压缩流的补丁文件(用hdiffz -SD-stepSize所创建) 那需要的内存大小: (oldFileSize+ stepSize + 1*解压缩缓冲区)+O(1); 如果diffFile是用hdiffz -BSD、bsdiff4所创建 那需要的内存大小: (oldFileSize + 3*解压缩缓冲区); 如果diffFile是VCDIFF格式补丁文件(用hdiffz -VCD、xdelta3、open-vcdiff所创建) 那需要的内存大小: (源窗口大小+目标窗口大小 + 3*解压缩缓冲区); -p-parallelThreadNumber 设置线程数 parallelThreadNumber>1 时,开启多线程并行模式; 当前只支持单压缩流的补丁文件(用hdiffz -SD-stepSize所创建); 可以设置值 1..5, 默认 -p-1 (即单线程)! -C-checksumSets 为文件夹patch设置校验方式, 默认设置为 -C-new-copy; 校验设置支持(可以多选): -C-diff 校验补丁数据; -C-old 校验引用到的旧版本的文件; -C-new 校验有修改过的新版本的文件; -C-copy 校验从旧版本直接copy到新版本的文件; -C-no 不执行校验; -C-all 等价于: -C-diff-old-new-copy; -C-no 或 -C-new 如果diffFile是VCDIFF格式补丁文件, 使用该选项可以关闭或打开校验,默认打开. -n-maxOpenFileNumber 为文件夹间的-s模式patch设置最大允许同时打开的文件数; maxOpenFileNumber>=8, 默认为24; 合适的限制值可能不同系统下不同。 -f 强制文件写覆盖, 忽略输出的路径是否已经存在; 默认不执行覆盖, 如果输出路径已经存在, 直接返回错误; 该模式支持oldPath和outNewPath为相同路径!(patch到一个临时路径,完成后再覆盖回old) 如果设置了-f,但outNewPath已经存在并且是一个文件: 如果patch输出一个文件, 那么会执行写覆盖; 如果patch输出一个文件夹, 那么会始终返回错误。 如果设置了-f,但outNewPath已经存在并且是一个文件夹: 如果patch输出一个文件, 那么会始终返回错误; 如果patch输出一个文件夹, 那么会执行写覆盖, 但不会删除文件夹中已经存在的无关文件。 -info 显示补丁的信息。 -v 输出程序版本信息。 -h 或 -? 输出命令行帮助信息 (该说明)。

库 API 使用说明:

diffpatch 函数在文件: libHDiffPatch/HDiff/diff.h & libHDiffPatch/HPatch/patch.h
dir_diff()dir patch 在: dirDiffPatch/dir_diff/dir_diff.h & dirDiffPatch/dir_patch/dir_patch.h

使用方式:

  • create diff(in newData,in oldData,out diffData); 发布 diffData 来升级 oldData。
  • patch(out newData,in oldData,in diffData); ok,得到了 newData。

v1 API, 未压缩补丁:

  • create_diff()
  • patch()
  • patch_stream()
  • patch_stream_with_cache()

v2 API, 压缩的补丁包:

  • create_compressed_diff()
  • create_compressed_diff_stream()
  • resave_compressed_diff()
  • patch_decompress()
  • patch_decompress_with_cache()
  • patch_decompress_mem()

v3 API, 在文件夹间 diff&patch:

  • dir_diff()
  • TDirPatcher_*() functions with struct TDirPatcher

v4 API, 单压缩流补丁包:

  • create_single_compressed_diff()
  • create_single_compressed_diff_stream()
  • resave_single_compressed_diff()
  • patch_single_stream()
  • patch_single_stream_mem()
  • patch_single_compressed_diff()
  • patch_single_stream_diff()

hpatch lite API, 为 MCU,NB-IoT... 优化了的 hpatch (例子 HPatchLite):

  • create_lite_diff()
  • hpatch_lite_open()
  • hpatch_lite_patch()
  • create_inplaceB_lite_diff()
  • hpatchi_inplace_open()
  • hpatchi_inplaceB()

bsdiff (bsdiff4 & endsley/bsdiff) 兼容包装 API:

  • create_bsdiff()
  • create_bsdiff_stream()
  • bspatch_with_cache()

vcdiff (open-vcdiff & xdelta3) 兼容包装 API:

  • create_vcdiff()
  • create_vcdiff_stream()
  • vcpatch_with_cache()

hsynz API, 同步 diff&patch (例子 hsynz):

  • create_sync_data()
  • create_dir_sync_data()
  • sync_patch()
  • sync_patch_...()
  • sync_local_diff()
  • sync_local_diff_...()
  • sync_local_patch()
  • sync_local_patch_...()
  • create_hdiff_by_sign() (patched by patch_single_stream()...)

zsync 兼容包装 API, (例子 hsynz):

  • create_zsync_data()
  • zsync_patch...()
  • zsync_local_diff...()
  • zsync_local_patch...()

测试用例(从 OneDrive 下载):

newFile <-- oldFilenewSizeoldSize
17-Zip_22.01.win.tar <-- 7-Zip_21.07.win.tar59089925748224
2Chrome_107.0.5304.122-x64-Stable.win.tar <-- 106.0.5249.119278658560273026560
3cpu-z_2.03-en.win.tar <-- cpu-z_2.02-en.win.tar87183368643072
4curl_7.86.0.src.tar <-- curl_7.85.0.src.tar2627584026030080
5douyin_1.5.1.mac.tar <-- douyin_1.4.2.mac.tar407940608407642624
6Emacs_28.2-universal.mac.tar <-- Emacs_27.2-3-universal.mac.tar196380160257496064
7FFmpeg-n_5.1.2.src.tar <-- FFmpeg-n_4.4.3.src.tar8052736076154880
8gcc_12.2.0.src.tar <-- gcc_11.3.0.src.tar865884160824309760
9git_2.33.0-intel-universal-mavericks.mac.tar <-- 2.31.07330252870990848
10go_1.19.3.linux-amd64.tar <-- go_1.19.2.linux-amd64.tar468835840468796416
11jdk_x64_mac_openj9_16.0.1_9_openj9-0.26.0.tar <-- 9_15.0.2_7-0.24.0363765760327188480
12jre_1.8.0_351-linux-x64.tar <-- jre_1.8.0_311-linux-x64.tar267796480257996800
13linux_5.19.9.src.tar <-- linux_5.15.80.src.tar12696371201138933760
14Minecraft_175.win.tar <-- Minecraft_172.win.tar166643200180084736
15OpenOffice_4.1.13.mac.tar <-- OpenOffice_4.1.10.mac.tar408364032408336896
16postgresql_15.1.src.tar <-- postgresql_14.6.src.tar151787520147660800
17QQ_9.6.9.win.tar <-- QQ_9.6.8.win.tar465045504464837120
18tensorflow_2.10.1.src.tar <-- tensorflow_2.8.4.src.tar275548160259246080
19VSCode-win32-x64_1.73.1.tar <-- VSCode-win32-x64_1.69.2.tar364025856340256768
20WeChat_3.8.0.41.win.tar <-- WeChat_3.8.0.33.win.tar505876992505018368

测试 PC: Windows11, CPU R9-7945HX, SSD PCIe4.0x4 4T, DDR5 5200MHz 32Gx2
参与测试的程序和版本: HDiffPatch4.6.3, hsynz 1.1.0, BsDiff4.3, xdelta3.1, zstd1.5.2
参与测试的程序的参数:
zstd --patch-from diff with --ultra -21 --long=24 -f --patch-from={old} {new} -o {pat}
zstd patch with -d -f --memory=2047MB --patch-from={old} {pat} -o {new}
xdelta3 diff with -S lzma -e -9 -n -f -s {old} {new} {pat}
xdelta3 patch with -d -f -s {old} {pat} {new}
& adding hpatchz test: hpatchz -m -f {old} {xdelta3-pat} {new}
xdelta3 -B diff with -S lzma -B {oldSize} -e -9 -n -f -s {old} {new} {pat}
xdelta3 -B patch with -B {oldSize} -d -f -s {old} {pat} {new}
& adding hpatchz test: hpatchz -m -f {old} {xdelta3-B-pat} {new}
bsdiff diff with {old} {new} {pat}
bspatch patch with {old} {new} {pat}
& adding hpatchz test: hpatchz -m -f {old} {bsdiff-pat} {new}
hdiffz -BSD diff with -m-6 -BSD -d -f -p-1 {old} {new} {pat}
hdiffz zlib diff with -m-6 -SD -d -f -p-1 -c-zlib-9 {old} {new} {pat}
hdiffz lzma2 diff with -m-6 -SD -d -f -p-1 -c-lzma2-9-16m {old} {new} {pat}
hdiffz zstd diff with -m-6 -SD -d -f -p-1 -c-zstd-21-24 {old} {new} {pat}
hdiffz -s zlib diff with -s-64 -SD -d -f -p-1 -c-zlib-9 {old} {new} {pat}
hdiffz -s lzma2 diff with -s-64 -SD -d -f -p-1 -c-lzma2-9-16m {old} {new} {pat}
hdiffz -s zstd diff with -s-64 -SD -d -f -p-1 -c-zstd-21-24 {old} {new} {pat}
& adding all hdiffz test with -p-8
hpatchz patch with -s-3m -f {old} {pat} {new}
hsynz test, make sync info by hsync_make -s-2k {new} {out_newi} {out_newz},
client sync diff&patch by hsync_demo {old} {newi} {newz} {out_new} -p-1
hsynz p1 zlib run hsync_make with -p-1 -c-zlib-9
hsynz p8 zlib run hsync_make with -p-8 -c-zlib-9 (run hsync_demo with -p-8)
hsynz p1 zstd run hsync_make with -p-1 -c-zstd-21-24
hsynz p8 zstd run hsync_make with -p-8 -c-zstd-21-24 (run hsync_demo with -p-8)

测试结果取平均:

程序包大小diff内存速度patch内存最大内存速度
bzip2-933.67%22.9MB/s66MB/s
zlib-936.53%19.8MB/s539MB/s
lzma2-9-16m25.85%5.3MB/s215MB/s
zstd-21-2427.21%4.2MB/s976MB/s
zstd --patch-from7.96%2798M3.3MB/s629M2303M828MB/s
xdelta313.60%409M6.9MB/s86M102M159MB/s
xdelta3 +hpatchz -m13.60%409M6.9MB/s70M82M377MB/s
xdelta3 -B9.63%2282M10.9MB/s460M2070M267MB/s
xdelta3 -B +hpatchz -m9.63%2282M10.9MB/s315M1100M477MB/s
bsdiff8.17%2773M2.5MB/s637M2312M167MB/s
bsdiff +hpatchz -m8.17%2773M2.5MB/s321M1101M197MB/s
hdiffz p1 -BSD7.72%1210M13.4MB/s14M14M172MB/s
hdiffz p8 -BSD7.72%1191M31.2MB/s14M14M172MB/s
hdiffz p1 zlib7.79%1214M14.4MB/s4M4M564MB/s
hdiffz p8 zlib7.79%1190M44.8MB/s4M4M559MB/s
hdiffz p1 lzma26.44%1209M11.4MB/s16M20M431MB/s
hdiffz p8 lzma26.44%1191M33.4MB/s16M20M428MB/s
hdiffz p1 zstd6.74%1211M11.5MB/s16M21M592MB/s
hdiffz p8 zstd6.74%1531M24.3MB/s16M21M586MB/s
hdiffz -s p1 -BSD11.96%91M46.0MB/s14M14M148MB/s
hdiffz -s p8 -BSD11.96%95M59.8MB/s14M14M148MB/s
hdiffz -s p1 zlib12.52%91M46.4MB/s3M4M611MB/s
hdiffz -s p8 zlib12.53%95M178.9MB/s3M4M609MB/s
hdiffz -s p1 lzma29.11%170M18.1MB/s17M20M402MB/s
hdiffz -s p8 lzma29.13%370M50.6MB/s17M20M400MB/s
hdiffz -s p1 zstd9.60%195M18.0MB/s17M21M677MB/s
hdiffz -s p8 zstd9.60%976M28.5MB/s17M21M678MB/s
hsynz p1 zlib20.05%6M17.3MB/s6M22M273MB/s
hsynz p8 zlib20.05%30M115.1MB/s13M29M435MB/s
hsynz p1 zstd14.96%532M1.9MB/s24M34M264MB/s
hsynz p8 zstd14.95%3349M10.1MB/s24M34M410MB/s

使用 Apk 文件来测试:

测试用例:

appnewFile <-- oldFilenewSizeoldSize
1cn.wps.moffice_eng_13.30.0.apk <-- 13.29.09590491894914262
2com.achievo.vipshop_7.80.2.apk <-- 7.79.9127395632120237937
3com.adobe.reader_22.9.0.24118.apk <-- 22.8.1.235872735143727087718
4com.alibaba.android.rimet_6.5.50.apk <-- 6.5.45195314449193489159
5com.amazon.mShop.android.shopping_24.18.2.apk <-- 24.18.07632885876287423
6com.baidu.BaiduMap_16.5.0.apk <-- 16.4.5131382821132308374
7com.dragon.read_5.5.3.33.apk <-- 5.5.1.324511265843518658
8com.ebay.mobile_6.80.0.1.apk <-- 6.79.0.16120258761123285
9com.eg.android.AlipayGphone_10.3.0.apk <-- 10.2.96122073135119046208
10com.google.android.apps.translate_6.46.0.apk <-- 6.45.04889296748843378
11com.google.android.googlequicksearchbox_13.38.11.apk <-- 13.37.10190539272189493966
12com.jingdong.app.mall_11.3.2.apk <-- 11.3.0101098430100750191
13com.netease.cloudmusic_8.8.45.apk <-- 8.8.40181914846181909451
14com.reddit.frontpage_2022.36.0.apk <-- 2022.34.05020511947854461
15com.sankuai.meituan.takeoutnew_7.94.3.apk <-- 7.92.27496589374833926
16com.sankuai.meituan_12.4.207.apk <-- 12.4.2059361373293605911
17com.sina.weibo_12.10.0.apk <-- 12.9.5156881776156617913
18com.smile.gifmaker_10.8.40.27845.apk <-- 10.8.30.27728102403847101520138
19com.ss.android.article.news_9.0.7.apk <-- 9.0.65444400353947221
20com.ss.android.ugc.aweme_22.6.0.apk <-- 22.5.0171683897171353597
21com.taobao.taobao_10.18.10.apk <-- 10.17.0117218670117111874
22com.tencent.mm_8.0.28.apk <-- 8.0.27266691829276603782
23com.tencent.mobileqq_8.9.15.apk <-- 8.9.13311322716310529631
24com.tencent.mtt_13.2.0.0103.apk <-- 13.2.0.00459734274797296757
25com.tripadvisor.tripadvisor_49.5.apk <-- 49.32874449828695346
26com.twitter.android_9.61.0.apk <-- 9.58.23614184035575484
27com.ubercab_4.442.10002.apk <-- 4.439.100026992323264284150
28com.ximalaya.ting.android_9.0.66.3.apk <-- 9.0.62.3115804845113564876
29com.xunmeng.pinduoduo_6.30.0.apk <-- 6.29.13089683330951567
30com.youdao.dict_9.2.29.apk <-- 9.2.28110624682110628778
31org.mozilla.firefox_105.2.0.apk <-- 105.1.08307846483086656
32tv.danmaku.bili_7.1.0.apk <-- 7.0.0104774723104727005

对测试程序的参数进行一些调整:
hdiffz ... -m-6 -SD changed to -m-1 -SD-2m -cache, -s-64 -SD changed to -s-16 -SD-2m
hdiffz ... lzma2 dict size 16m changed to 8m, zstd dict bit 24 changed to 23
hsynz ... make -s-2k changed to -s-1k
& adding hsynz p1, hsynz p8 make without compressor
archive-patcher v1.0, diff with --generate --old {old} --new {new} --patch {pat},
patch with --apply --old {old} --patch {pat} --new {new}
注意: archive-patcher 统计的补丁包大小是经过了 lzma2-9-16m 压缩后的, 而 diff&patch 统计时并不包含压缩和解压缩补丁所需的内存和时间。
sfpatcher -1 zstd v1.1.1 diff with -o-1 -c-zstd-21-23 -m-1 -step-3m -lp-512k -p-8 -cache -d {old} {new} {pat}
& sfpatcher -2 lzma2 diff with -o-2 -c-lzma2-9-4m -m-1 -step-2m -lp-8m -p-8 -cache -d {old} {new} {pat}
sfpatcher -1 clA zstd v1.3.0 used $sf_normalize -cl-A normalized apks before diff
sfpatcher patch with -lp -p-8 {old} {pat} {new}
adding test hpatchz&sfpatcher on Android, arm CPU 麒麟980(2×A76 2.6G + 2×A76 1.92G + 4×A55 1.8G)
( archive-patchersfpatcher diff&patch 时针对apk文件格式进行了优化 )

测试结果取平均:

程序包大小diff内存速度patch内存最大内存速度arm 麒麟980
zstd --patch-from53.18%2199M3.6MB/s209M596M609MB/s
xdelta354.51%422M3.8MB/s98M99M170MB/s
xdelta3 +hpatchz -m54.51%422M3.8MB/s70M81M438MB/s
bsdiff53.84%931M1.2MB/s218M605M54MB/s
bsdiff+hpatchz -m53.84%931M1.2MB/s116M310M57MB/s
bsdiff+hpatchz -s53.84%931M1.2MB/s14M14M54MB/s
hdiffz p1 -BSD53.69%509M6.8MB/s14M14M55MB/s
hdiffz p8 -BSD53.70%514M15.3MB/s14M14M55MB/s
hdiffz p154.40%509M8.8MB/s5M6M682MB/s
hdiffz p854.41%514M32.4MB/s5M6M686MB/s443MB/s
hdiffz p1 zlib53.21%509M8.2MB/s5M6M514MB/s
hdiffz p8 zlib53.22%514M31.1MB/s5M6M512MB/s343MB/s
hdiffz p1 lzma252.93%525M4.1MB/s21M22M260MB/s
hdiffz p8 lzma252.94%557M18.9MB/s21M22M261MB/s131MB/s
hdiffz p1 zstd53.04%537M5.4MB/s21M22M598MB/s
hdiffz p8 zstd53.05%1251M11.1MB/s21M22M604MB/s371MB/s
hdiffz -s p1 zlib53.73%118M26.8MB/s4M6M513MB/s
hdiffz -s p8 zlib53.73%122M97.3MB/s4M6M513MB/s
hdiffz -s p1 lzma253.30%197M6.4MB/s20M22M258MB/s
hdiffz -s p8 lzma253.30%309M32.4MB/s20M22M258MB/s
hdiffz -s p1 zstd53.44%221M10.1MB/s20M22M620MB/s
hdiffz -s p8 zstd53.44%1048M14.4MB/s20M22M613MB/s
hsynz p162.43%4M1533.5MB/s4M10M236MB/s
hsynz p862.43%18M2336.4MB/s12M18M394MB/s
hsynz p1 zlib58.67%5M22.7MB/s4M11M243MB/s
hsynz p8 zlib58.67%29M138.6MB/s12M19M410MB/s
hsynz p1 zstd57.74%534M2.7MB/s24M28M234MB/s
hsynz p8 zstd57.74%3434M13.4MB/s24M28M390MB/s
archive-patcher31.65%1448M0.9MB/s558M587M14MB/s
sfpatcher-1 p1 zstd31.08%818M2.3MB/s15M19M201MB/s92MB/s
sfpatcher-1 p8 zstd31.07%1025M4.6MB/s18M25M424MB/s189MB/s
sfpatcher-2 p1 lzma224.11%976M2.1MB/s15M20M37MB/s19MB/s
sfpatcher-2 p8 lzma224.15%968M5.0MB/s20M26M108MB/s45MB/s
sfpatcher-1 p1 clA zstd21.72%1141M2.5MB/s19M22M85MB/s63MB/s
sfpatcher-1 p8 clA zstd21.74%1156M5.4MB/s26M29M240MB/s129MB/s

联系

housisong@hotmail.com