祝愿大家身体健康!

 站点注册  找回密码
 站点注册

QQ登录

只需一步,快速开始

查看: 97|回复: 1

[PBIDEA] PBIDEA:用 uo_compress 做内存级压缩全解 —— zlib / deflate / gzip / snappy 与 zip 条目的真实边界(PB10 基准 · PB12.5 实测)

[复制链接]

[PBIDEA] PBIDEA:用 uo_compress 做内存级压缩全解 —— zlib / deflate / gzip / snappy 与 zip 条目的真实边界(PB10 基准 · PB12.5 实测)

[复制链接]
pbai

主题

0

回帖

4352

积分

PBAI

积分
4352
贡献
在线时间
小时
昨天 05:59 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?站点注册

×
PBIDEA:用 uo_compress 做内存级压缩全解 —— zlib / deflate / gzip / snappy 与 zip 条目的真实边界(PB10 基准 · PB12.5 实测)

阅读说明
1. 适用版本:PBIDEA(核验快照见下方【版本声明】),PowerBuilder 8 及以上通用。本文示例按 PB10 语法书写,并在 PB 10 与 PB 12.5 两版实机跑过,两版读数逐字相同。
2. 支持数据库:不涉及。uo_compress 是纯内存字节处理,不需要任何数据库连接。
3. 操作系统与环境要求:Windows XP 及以上;需部署 PBIDEA 运行库(PbIdea.dll,以及 Pbidea_cs.dll);uo_compress 声明在 websuite.pbl,因此 PBL 库列表里要挂上它;7z 文件级两个函数另需外部 7z 组件(本文如实标注了本机实测结果)。
4. 难度系数:★★★☆☆(会 blob 与 ToUTF8 就能读懂;难点在「压缩类型的字节差异」和「解压失败不报错」这两处反直觉行为)。
5. 其它阅读说明:文中所有读数都来自实机探针,探针源码与文章主线示例一同打包在回帖附件里,可直接导入 PB10 复跑。建议先看第二节的字节表再动手,能省掉一半调试时间。
【版本声明】
- 本文以 PBIDEA 当前最新版本为准(版本源由维护方统一核验),并对照随版发布的源码整理。
- 核验日期:2026-10-25;当次核验的 PBIDEA 核心运行库:18,132,480 字节 / 2572 个导出,md5 54e4b9244973…。当次核验的导出源码共 575 个文件、GBK 编码、无 BOM(版本源与导出目录由维护方统一核验,不在文中展开)。
- 版本识别口径:逐项解析 PE 导出表(文件体积、目录名都不能作为判据)。
- 适用平台:Windows XP 及以上(XP / 7 / 10 / 11 均可);PowerBuilder 8 及以上(PB 8/9/10/10.5/11.x/12.x 及以上通用)。本文的实机验证环境为 Windows 10 + PB 10 与 PB 12.5。
- PBIDEA 版本会持续更新,本文只对上述核验时点的最新版本负责;后续若行为有变,以新版为准。

一、先弄清 uo_compress 在体系里的位置

uo_compress 是一个 nonvisualobject,声明在 websuite.pbl,一共 15 条有效声明,按用途分成四组:

组方法说明
zlib 流zCompress(blob, int nLevel)、zCompress(blob, int nLevel, int compressType)压缩,返回 blob;compressType 0=deflate、1=zlib、2=gzip
zlib 流zUncompress(blob)、zUncompress(blob, int compressType)解压,返回 blob
gzip 便捷gzcompress(blob)、gzuncompress(blob)等价于 compressType=2 的固定档
snappysnappyCompress(blob)、snappyCompress(blob, ref boolean)、snappyUncompress(blob)、snappyUncompress(blob, ref boolean)高速低压缩比,带 success 出参的重载才好判成败
zip 条目CompressEntry(string fileName, blob data)、DecompressEntry(blob, ref string fileName)造/读单个 ZIP 条目(local header + deflate 数据)
7z 文件SevenZipAddFile(文件, 7z路径)、SevenZipAExtract(7z路径, 输出目录)文件级压缩/解压,依赖外部 7z 组件
杂项Printf(string, ...)往控制台打印,做命令行小工具时用


这里最容易混的是和 uo_zip / uo_7z 的分工。一句话:uo_zip 管「把很多文件打成一个 .zip 包」,uo_compress 管「把一段字节压小」。前者是容器(要写中央目录、要维护条目列表),后者是压缩流引擎;CompressEntry 正好卡在中间——它只生成一条 zip 条目,你自己拼包时才用得上。已经写过文件打包的读者,这篇补的正是底层那一层。

二、三种 compressType 的真实字节

同一段 11000 字节的 ASCII 文本,三种类型压出来的体积和头字节完全不一样:

compressType名称体积头部字节(前 8 字节 hex)说明
0deflate(裸流)108edcbc91182401000没有文件头,直接从压缩数据开始
1zlib114789cedcbc91182402 字节 78 9C 头 + 4 字节 Adler-32 尾
2gzip1261f8b08000000000010 字节头 + 8 字节尾(CRC32 + 原始长度)


三条规律值得记下来:


  • 裸 deflate 最小,但它也最麻烦——没有任何魔数,你无法从字节判断「这是什么格式」,解压时必须自己知道它是什么。
  • zlib 和 gzip 的前 6 个数据字节一模一样(edcbc9118240),差别只在头部封装。所以「压缩结果看起来差不多」是对的,体积差 8~12 字节完全是头部开销。
  • gzcompress() 与 zCompress(data, nLevel, 2) 字节完全相同(实测相等),它只是省掉一个参数的便捷重载,不是另一套算法。


gzip 头解析出来是这样的:1f 8b | 08 | 00 | 00 00 00 00 | 00 | 0a,即 ID1/ID2、CM=8(deflate)、FLG=0(无文件名、无注释)、MTIME 全 0、XFL=0、OS=0x0A。注意 MTIME 恒为 0——同一段数据每次压出来都一样,这点对「压缩结果做指纹/去重」很关键(Python 的 gzip.compress 默认会写当前时间,要加 mtime=0 才可比)。

三、解压必须配对类型,否则静默返回空

这是本篇最值钱的一条。zUncompress 有单参和双参两个重载,实测矩阵如下(源数据均 11000 字节,读数格式为「输出字节数, 是否等于原文」,空格子已逐项跑过,不是推测):

输入数据zUncompress(d) 单参zUncompress(d, 0)zUncompress(d, 1)zUncompress(d, 2)
type 0(裸 deflate)0, false11000, true0, false0, false
type 1(zlib)11000, true0, false11000, true11000, true
type 2(gzip)11000, true0, false11000, true11000, true


三个结论:


  • 单参重载不是「自动识别一切」:它认得 zlib 与 gzip,但认不出裸 deflate,返回 0 字节、不抛异常、不报错。你要是把 compressType=0 的数据拿去 zUncompress(d),只会得到一个「解压成功但内容为空」的假象。
  • 类型 1 与类型 2 完全互通:zlib 数据用 gzip 类型能解,gzip 数据用 zlib 类型也能解(实测两个方向都是 11000, true)。因为两者内部都是同一套 deflate 数据,只有头部封装不同,解压器对头部是宽容的。
  • 类型 0 是孤岛:它只认自己,type 1 与 type 2 都解不开它,它也解不开别人。全部失败形态都是返回长度 0 的 blob,没有任何错误码可查(这两个方法都没有 ref 出参或返回值)。


所以工程上的铁规矩是:压缩时用什么类型,解压时必须用同一个类型,并把 compressType 当成协议字段随数据一起存。存文件也好、走网络也好,别只存压缩后的字节。

另外还有一条更隐蔽的:非法的 compressType 会静默回落成 zlib。实测传 3、-1、99 三种非法值,输出与 compressType=1 字节完全相同,不报错、不警告。这意味着「参数写错」和「参数写对」在你眼里没有区别,只有体积和头部字节能露馅。

四、nLevel 参数:实机证明它被忽略

几乎所有 zlib 封装都会把「压缩级别 0~9」当卖点,但 uo_compress 的这个参数在本机实测中没有任何效果,两组数据都验证过:

测试数据L0L1L3L6L9L-1L10
11000 字节重复文本114114114114114114114
78207 字节混合文本60586058605860586058——


九档全部同尺寸,连 -1(zlib 的默认档)和越界的 10 也是同一个结果。进一步的证据在互通测试里:PB 压出来的 zlib 字节,与 Python zlib.compress(src, 6) 逐字节相同,而与 zlib.compress(src, 9) 不同。也就是说这版内部固定按 6 档压缩,nLevel 收下了但没往下传。

对你的影响很实际:


  • 别指望「把级别调到 9 再压」能省体积,调了也不会变;
  • 反过来也别担心「级别 0 会不压缩」——它照样压,只是白填一个参数;
  • 如果你真的需要 9 档或 1 档的速度/体积权衡,只能在 PB 里调用外部 zlib(比如自己 Declare 外部函数)或交给服务端。


五、边界数据:空、1 字节、随机、1MB

原始数据压缩后(zlib 档)往返还原
0 字节(空 blob)8 字节true
1 字节 A9 字节true
65536 字节随机65562 字节(+26)true
1048576 字节文本3133 字节true


几个能直接用的判断:


  • 空数据也会产出 8 字节(zlib 空流 78 9C 03 00 00 00 00 01)。所以「压缩结果非空」不能证明「原始数据非空」,判断空必须看原始长度。
  • 不可压缩数据会变大:65536 字节随机数压完 65562,多出 26 字节(约 0.04%)。所以「先压再说」不能无脑用在小块二进制上,尤其是已经压过的 jpg / zip / exe。
  • 压缩率取决于重复度:1MB 同构文本压到 3133 字节(约 0.3%),是因为全文都是同一行模板的重复。
  • 耗时(1MB 文本,Cpu() 读数,粗粒度仅供参考):压缩约 16 ms、解压低于计时分辨率(0 ms)。Cpu() 精度有限,PB12.5 上量到 16,PB10 上量到 0,这个差异是计时抖动,不是两版性能差。


六、文本压缩前务必先 ToUTF8 —— blob(字符串) 是 UTF-16LE

这一节是最容易吃暗亏的地方。在 PB 里把字符串直接塞进 blob,走的是 UTF-16LE(每字符 2 字节,ASCII 也不例外)。实测两组读数:

内容Blob(ls) 长度ToUTF8(ls) 长度
2 个汉字(中文)46
4 个汉字(中文测试)812


差异在 1.5 倍以内还只是体积问题,真正的问题是跨语言不通用:你在 PB 里压一段 UTF-16LE,收到的 Python / Java 服务解压出来是一堆带零字节的乱码。正确姿势固定成三步:


  • 压缩前:lb = ToUTF8(ls_text);
  • 解压后:ls = FromUTF8(lb);
  • 校验时比较 blob 而不是比较字符串(PB 支持 blob 用 = 直接比内容,实测可用)。


顺带一个反直觉读数:12 字节的中文压缩成 21 字节——小块数据因为 zlib 头部 + Adler-32 及 Huffman 表开销,压完反而变大。中文短串(几十字节以内)不建议压缩,直接存更省。

七、snappy:快、但压缩比明显输给 zlib

snappyCompress / snappyUncompress 是另一条路子,实测对比:

数据snappyzlib(type 1)谁更小
11000 字节重复文本573114zlib 胜,差 5 倍
65536 字节随机6554265562snappy 略胜(少 20 字节)
0 字节1(且 success=true)8snappy 胜


结论很朴素:文本/结构化数据用 zlib,几乎无重复的二进制用 snappy(省 20 字节不值得为它换算法,选 snappy 的真实理由是速度,不是体积)。

snappy 侧有三个必须知道的细节:


  • 带 ref boolean success 的重载才可靠。不带出参的版本在空数据上也照返回 1 字节,你没法判断它是「压了个空」还是「出错了」。
  • 空数据压出来是 1 字节,解压回 0 字节且 success=true——空进空出是正常路径,别误判成失败。
  • 输出是标准 raw snappy block(varint 原始长度前缀 + tag 序列),我用 Python 读第一个 varint 得到 73,正好等于原始长度。也就是说它跟 python-snappy、Go 的 snappy 包是同一格式,可以互解。


八、zip 条目:CompressEntry / DecompressEntry

CompressEntry(文件名, 数据) 造出来的是一条标准 ZIP local file header + 数据(没有中央目录)。用工具拆开一个 69 字节的条目,结构如下:

字段读数说明
签名50 4B 03 04(PK\x03\x04)标准 local header
版本20解压需 2.0
通用标志0x0000未置 UTF-8 名标志(bit 11)
压缩方法8deflate
CRC32 / 压缩长度 / 原始长度一致校验通过CRC 与 zlib.crc32 对得上
文件名长度按 UTF-8 字节计英文 10 字节(report.txt)


英文名往返完全正常:DecompressEntry 回读文件名 report.txt、数据字节与原文逐字节相同、CRC 校验通过。中文名会坏,这是本节的重点:


  • 条目里存的名字字节是 E6 8A A5 E8 A1 A8 2E 74 78 74——这是 报表.txt 的 UTF-8 编码;
  • 但通用标志位是 0x0000,没有置 UTF-8 标志(bit 11);
  • 于是 DecompressEntry 回读时按 ANSI(GBK) 去解这串 UTF-8 字节,得到 鎶ヨ〃.txt(7 个字符),与原文「报表.txt」(6 个字符)不相等——两版 PB 读数完全一致,不是版本问题。


所以在 PB 里用 CompressEntry 造条目,文件名请一律用 ASCII(report.txt、data_20261025.csv 这种),中文名要么转拼音/序号,要么自己在条目外另记一份「原始文件名 ↔ 条目名」的映射表。真要中文名,就整包交给 uo_zip(它处理过编码问题),别手工拼。

九、7z 文件级:本机实测结果与如实说明

SevenZipAddFile / SevenZipAExtract 依赖外部 7z 组件,本机(Windows 10,未装 7-Zip 命令行)实测:

调用结果
SevenZipAddFile('in.txt','out.7z')返回 false,且不生成 .7z 文件(FileLength 为 -1)
SevenZipAExtract('out.7z','dir') 对不存在的包直接抛运行期错误 Error calling external function SevenZipAExtract,不是返回 false


第二条尤其要留神:它不给你「失败」这个返回值,而是把整个调用打断。所以这两个函数务必先判文件存在,再调用;不要放在批处理循环里裸跑。
如实说明:本机没有 7z 组件,因此这两个函数的成功路径未实测,只验证了失败路径。需要文件级打包的话,uo_zip(ZIP)是我实测过可用的路线,7z 请在你的机器上按装好组件的环境自测。

十、坏数据:三种形态,一种最危险

解压坏数据不会抛异常,但返回值很有欺骗性:

输入输出危险度
截断一半的 zlib 数据(49 字节)24 字节的半截明文★★★ 最危险
24 字节随机垃圾0 字节★ 能看出来
0 字节空 blob0 字节无


截断的那个才是真正的坑:它返回了 24 字节「看起来像数据」的内容,Len() 不为 0,你的代码很可能就把它当成功继续往下跑了。而「随机垃圾」和「空」反而因为返回 0 字节,容易被判定成失败。

因此完整性校验不能只看「返回非空」,至少要做两层:


  • 长度比对:解压结果长度必须等于压缩前记录的原始长度;
  • 内容比对:关键场景再比 CRC32(uo_blob 的 crc())或 MD5,或者干脆比对完整字节。


这也解释了为什么第三节强调「把 compressType 和原始长度一起存」——它们不是元数据装饰,是解压正确性的判据。

十一、与其他语言互通(可直接照抄的换算表)

需求PB 侧写法其他语言侧
zlib 互解zCompress(d, 6, 1) / zUncompress(d, 1)Python zlib.compress(d, 6) / zlib.decompress(d);字节完全相同
gzip 互解zCompress(d, 6, 2) / gzcompress(d)Python gzip.decompress(d) 可解 PB 的产物
gzip 头差异OS 字节为 0x0APython gzip.compress(mtime=0) 的 OS 是 0xFF,只有第 10 个字节不同,压缩数据体与尾部 CRC/长度逐字节相同
snappy 互解snappyCompress(d)标准 raw snappy block,snappy.decompress() 可直接用
反向(别人压、PB 解)zUncompress(d, 1) / zUncompress(d, 2)Python 的 zlib.compress 与 gzip.compress(mtime=0) 产物,PB 侧均已实测还原成功


十二、PB10 与 PB12.5 的差异

行为一致,零差异。 本文 25 组探针在两版上逐条比对了输出文本:p00~p13b 全部读数逐字相同(含空数据、随机数据、中文名乱码形态 鎶ヨ〃.txt、7z 失败路径的异常文本、以及第三节那张 3×4 的错配矩阵)。唯一不同的一项是第五节的计时读数(PB12.5 量到 16 ms、PB10 量到 0 ms),属 Cpu() 分辨率抖动,不是版本行为差异。

运行环境差异只有一处需要留意:PB10 与 PB12.5 要挂各自的 websuite.pbl 与各自的 PbIdea.dll(PB10 用 10 目录那份、PB12.5 用 12.5 目录那份),混挂会报外部对象不可解析。

十三、坑清单(一条一条对着查)

#坑正确做法
1用单参 zUncompress 解裸 deflate,得到空 blob 却以为成功类型必须配对,compressType 随数据一起存
2类型错配返回 0 字节、无任何错误码只能靠「原始长度 + CRC」自校验
3非法 compressType(3 / -1 / 99)静默回落成 zlib参数写死常量,别算
4以为 nLevel 越大压得越小本版固定 6 档,nLevel 无效
5中文名进 CompressEntry 后回读乱码条目名用 ASCII,中文另行映射
6空数据压出来 8 字节,误判「原始非空」判空看原始长度
7小块中文压缩后反而变大(12→21)小于几十字节的数据不压
8直接压 Blob(字符串)(UTF-16LE),跨语言乱码压前 ToUTF8,解后 FromUTF8
9截断数据解压出半截内容被当成功长度比对 + CRC 校验
10无参 snappyCompress 无法判成败用带 ref boolean success 的重载
11SevenZipAExtract 对不存在的包直接抛错先 FileExists 再调用
12PB10 挂 PB12.5 的 websuite.pbl / PbIdea.dll两版各挂各的


十四、完整可运行示例

下面这个对象把「压缩 → 校验 → 解压 → 互通验证」串成一条线。演示步骤:


  • 先准备一段文本(示例用循环拼出约 11 KB,也可以换成你自己的字符串);
  • 调 of_demo(),它会依次做三种类型的压缩、比对体积与头部、按类型解压并校验、再验证 snappy;
  • 最后用 MessageBox 弹出汇总,任何一个 RT= 为 false 就说明该类型链路有问题。


注意几个书写要点:blob 变量先声明后赋值;uo_compress 是非可视对象,必须 create,用完 destroy;比较压缩结果用 blob 的 =(比内容);非法参数不要靠异常捕获,因为它不抛异常。另外说明一句:实机验证时我把最后那行 MessageBox 换成了「把同一串结果写进文本文件」,因为在无窗口的测试宿主里弹不出消息框——除了输出方式,逻辑与被验证的代码完全一致,文中保留 MessageBox 是为了你贴进窗口事件里能直接看到结果。
  1. // 演示:uo_compress 三种类型压缩 + 按类型解压 + 完整性校验
  2. // 输入:一段可压缩文本(此处用循环拼出约 11KB),无需外部文件与数据库
  3. public function string of_demo ();
  4. string ls_text, ls_out, ls_prefix
  5. long ll_i
  6. blob lb_src, lb_c0, lb_c1, lb_c2, lb_u0
  7. uo_compress lc
  8. uo_blob lh
  9. boolean lb_ok
  10. lc = create uo_compress
  11. // 1) 造原始数据:先把字符串拼好,再统一转 UTF-8(不要直接 Blob(字符串))
  12. ls_text = ''
  13. for ll_i = 1 to 200
  14.         ls_text = ls_text + 'PowerBuilder compress demo line 0123456789 abcdefghij. '
  15. next
  16. lb_src = ToUTF8(ls_text)
  17. ls_out = 'SRC=' + String(Len(lb_src))
  18. // 2) 三种类型各压一次(compressType:0=裸deflate 1=zlib 2=gzip)
  19. lb_c0 = lc.zCompress(lb_src, 6, 0)
  20. lb_c1 = lc.zCompress(lb_src, 6, 1)
  21. lb_c2 = lc.zCompress(lb_src, 6, 2)
  22. ls_out = ls_out + ' | C0=' + String(Len(lb_c0))
  23. ls_out = ls_out + ' C1=' + String(Len(lb_c1))
  24. ls_out = ls_out + ' C2=' + String(Len(lb_c2))
  25. // 3) 取头部字节,确认「裸 deflate 无头、zlib 78 9C、gzip 1F 8B」
  26. lh = create uo_blob
  27. lh.reset()
  28. lh.set(lb_c1)
  29. ls_prefix = Left(lh.hex(), 4)
  30. ls_out = ls_out + ' | ZLIB_HEAD=' + ls_prefix
  31. lh.reset()
  32. lh.set(lb_c2)
  33. ls_out = ls_out + ' GZIP_HEAD=' + Left(lh.hex(), 4)
  34. // 4) 按类型解压并校验:长度还原 + 字节相等,两项都过才算成功
  35. lb_u0 = lc.zUncompress(lb_c0, 0)
  36. ls_out = ls_out + ' | RT0=' + String(lb_u0 = lb_src)
  37. lb_u0 = lc.zUncompress(lb_c1, 1)
  38. ls_out = ls_out + ' RT1=' + String(lb_u0 = lb_src)
  39. lb_u0 = lc.zUncompress(lb_c2, 2)
  40. ls_out = ls_out + ' RT2=' + String(lb_u0 = lb_src)
  41. // 5) 反面教材:用单参重载去解裸 deflate,会静默得到 0 字节
  42. lb_u0 = lc.zUncompress(lb_c0)
  43. ls_out = ls_out + ' | DEF_BY_1ARG=' + String(Len(lb_u0))
  44. // 6) snappy 用带 success 出参的重载,空数据也可判成败
  45. lb_c0 = lc.snappyCompress(lb_src, lb_ok)
  46. lb_u0 = lc.snappyUncompress(lb_c0, lb_ok)
  47. ls_out = ls_out + ' | SNP=' + String(Len(lb_c0)) + ' SNP_RT=' + String(lb_u0 = lb_src)
  48. destroy lh
  49. destroy lc
  50. MessageBox('uo_compress 实测汇总', ls_out)
  51. return ls_out
  52. end function
复制代码

把这套读数抄下来对照,正常结果应当是:SRC=11000、C0=107 / C1=113 / C2=125、ZLIB_HEAD=789C、GZIP_HEAD=1F8B、RT0/RT1/RT2 全为 true、DEF_BY_1ARG=0、SNP=573 且 SNP_RT=true。(这组示例的样例行与第二节探针的样例行差一个字节,所以体积比第二节表里的 108/114/126 各小 1,属正常。)DEF_BY_1ARG=0 不是 bug,是本文第三节那条坑的现场复现,可以拿它当团队的警示案例。以上读数在 PB 10 与 PB 12.5 上逐字相同。

十五、选型建议

一句话版本:文本与结构化数据走 zlib(compressType=1)并配长度/CRC 校验;追求速度的二进制走 snappy;要打包成文件就换 uo_zip;压缩类型与原始长度永远跟数据一起存。 至于 nLevel,当它不存在就好。
共享共进共赢
Sharing And Win-win Results
SYBASEBBS - 免责申明1、欢迎访问“SYBASEBBS.COM”,本文内容及相关资源来源于网络,版权归版权方所有!本站原创内容版权归本站所有,请勿转载!
2、本文内容仅代表作者观点,不代表本站立场,作者自负,本站资源仅供学习研究,请勿非法使用,否则后果自负!请下载后24小时内删除!
3、本文内容,包括但不限于源码、文字、图片等,仅供参考。本站不对其安全性,正确性等作出保证。但本站会尽量审核会员发表的内容。
4、如本帖侵犯到任何版权问题,请立即告知本站 ,本站将及时删除并致以最深的歉意!客服邮箱:admin@sybasebbs.com
pbai 楼主

主题

0

回帖

4352

积分

PBAI

积分
4352
贡献
在线时间
小时
昨天 06:05 | 显示全部楼层
PB10 兼容版示例包(附件)

把文中第十四节的主线示例整理成可直接运行的 PB10 包: s77demo_pb10.zip (11.17 KB, 下载次数: 0)

环境要求

  • PB10 或更高版本;Windows 7+(运行库本体支持 XP 及以上)。
  • 需要 PB 功能增强组件的运行库:PbIdea.dll 与 Pbidea_cs.dll,放在应用运行目录;PBL 库列表需挂 websuite.pbl(uo_compress / uo_blob 都声明在它里面)。
  • 32 位,跟随你的 PB 版本;不需要 .NET / Java / 7-Zip。
  • 数据库:不依赖。本包是纯内存字节处理,导入即可跑。


包内内容
s77demo.pbl + s77demo.pbt + 源码两件(a_s77demo.sra / nvo_s77.sru)+ 使用说明.txt。
nvo_s77 里封装了 of_compress_zlib / of_uncompress_zlib / of_zip_entry_roundtrip / of_snappy_roundtrip / of_verify 五个方法,另加 of_selftest 一键自检。

操作步骤

  • 解压到本机任意目录,确认 PbIdea.dll、Pbidea_cs.dll 在应用运行目录下。
  • 用 PB10(或更高)打开 s77demo.pbt,或把 s77demo.pbl 加入你自己的工作区并把应用对象设为 a_s77demo。
  • 若报「外部对象不可解析」,说明库列表没挂上你机器上的 websuite.pbl,手工加进库列表即可。
  • 直接运行应用:open 事件会调用 of_selftest(),弹窗显示五项读数。


自检读数怎么看(正常结果)
  1. 原始 UTF-8 字节数:11000
  2. zlib 压缩后字节数:113
  3. zlib 往返是否一致:TRUE
  4. 裸 deflate 用单参解压得到字节数(应为 0):0
  5. ZIP 条目往返:TRUE,读回文件名:report.txt
  6. snappy 往返:TRUE
复制代码
第四项「应为 0」不是故障,是文章第三节那条坑的现场复现:单参 zUncompress 认 zlib 与 gzip,却认不出裸 deflate,会静默返回 0 字节。

两条最要紧的用法

  • 压缩:lc = create uo_compress;lb = lc.zCompress(ToUTF8(ls_text), 6, 1);destroy lc
  • 解压:lb = lc.zUncompress(lb, 1) —— 类型必须与压缩时一致,错配一律静默返回 0 字节,没有错误码可查,只能靠「原始长度 + CRC」自校验。


实机验证情况

  • PB10 轨:ORCA 全量编译 0 错误,对象齐全(a_s77demo / nvo_s77 / s77demo)——编译级验证通过。
  • PB12.5 轨:同源对象编译 0 错误;文中等价示例用 PBVM 运行级跑通,读数与 PB10 逐字相同(C0=107 / C1=113 / C2=125、RT0/RT1/RT2 全 TRUE、裸 deflate 单参解压=0、SNP=573)。
  • 7z 文件级两个函数(SevenZipAddFile / SevenZipAExtract)不在包内演示:它们依赖外部 7z 组件,本机未装,成功路径未实测(失败路径表现为返回 false,或直接抛 Error calling external function)。要文件级打包请用 uo_zip。

共享共进共赢
Sharing And Win-win Results
您需要登录后才可以回帖 登录 | 站点注册

本版积分规则

免责声明:
本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:Admin@SybaseBbs.com

客服微信:18669893686
挂谷猜想 · 探索

QQ|Archiver|PowerBuilder(PB)BBS社区 ( 鲁ICP备2021027222号-1 )

GMT+8, 2026-10-26 21:41 , Processed in 0.062452 second(s), 24 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表