pbai 发表于 2026-8-26 07:21:17

PBIDEA:用 uo_zip 与 uo_7z 在 PowerBuilder 里做 ZIP 与 7z 压缩解压

PBIDEA:用 uo_zip 与 uo_7z 在 PowerBuilder 里做 ZIP 与 7z 压缩解压


阅读说明
1. 适用版本:PB 12.5 及以上(含 PBIDEA 1.x;uo_zip / uo_7z 依赖 PbIdea.dll 运行库)
2. 支持数据库:本文为纯文件操作,不涉及数据库
3. 操作系统与环境要求:Windows 7+,已安装 PBIDEA 运行库(PbIdea.dll 等)
4. 难度系数:★★★☆☆
5. 其它阅读说明:示例中的路径请替换为你本机真实路径;uo_zip 与 uo_7z 位于 websuite.pbl,需将该 pbl 加入工程,并随应用一起分发 PbIdea.dll


做桌面应用绕不开"打包":导出一批报表、把日志归档、把更新包发给客户、把多个文件合成一个附件上传……这些场景在 PB 里不需要调用外部 exe,PBIDEA 的 uo_zip 和 uo_7z 两个对象就能直接搞定。一个产出通用的 ZIP(Windows 资源管理器原生能打开),一个产出压缩率更高的 7z。本文把这两个对象的全部 API、典型用法、内存压缩、目录遍历配合、以及常见坑一次讲透。

一、两个对象各自的定位


[*]uo_zip:封装 ZIP 格式的压缩与解压。支持加密码、加注释、按条目读取、把 blob 直接打包(不落盘)。底层是 PbIdea.dll 的 zip* 系列函数,对象 constructor 自动 zipCreate()、destructor 自动 zipDestroy(),所以必须 create / destroy,不能当 autoinstantiate 用。
[*]uo_7z:封装 7z 格式的压缩与解压(基于 7-Zip 内核)。除了能压整个目录/文件成 .7z,还提供 blob 级别的内存 7z 压缩(自定义格式,注意只能用 Uncompress7Z 还原)。同样是 constructor 自动 SevenZipCreate()、destructor 自动 SevenZipDestroy(),也要 create / destroy。


一句话选型:要兼容性选 uo_zip(ZIP),要更高压缩率选 uo_7z(7z);如果只是想在网络传输前把一段二进制数据压小,两个对象都支持纯内存 blob 压缩。

二、uo_zip 完整 API 清单

下面是 uo_zip 对外暴露的全部方法(均来自 PbIdea.dll,已逐一核对源码原型):


方法说明
boolean Open(string strZipFile)打开(不存在则创建)压缩包,无密码
boolean Open(string, boolean bReadOnly)指定是否只读
boolean Open(string, boolean bReadOnly, string strPassword)带密码打开(创建加密包或读加密包)
boolean Open(blob zipBuffer, string strPassword)直接从内存 blob 只读打开
boolean IsOpen()是否已打开
Close()提交所有操作并真正写入磁盘(相当于 commit)
Discard()放弃本次操作(相当于 rollback)
boolean Add(string strZipFile)加入一个物理文件
long AddPath(string strPath)加入整个目录(自动保留子目录结构)
boolean Add(string strName, blob data)把一段 blob 作为条目加入(不依赖物理文件)
long GetEntryCount()条目总数
boolean EntryExist(string strName)某条目是否存在
boolean DeleteEntry(string strName)删除条目
boolean RenameEntry(string strName, string strNewName)重命名条目
long GetEntryList(ref ...7个数组)枚举全部条目元信息
blob ReadBlob(long index) / blob ReadBlob(string strName)按索引或名称读取条目内容为 blob
long Extract(string strPath)解压全部到目录
long Extract(string strPath, long index)按索引解压单个条目
long Extract(string strPath, string strName)按名称解压单个条目
SetComment / GetComment压缩包注释
DeleteFile()删除整个 zip 文件
blob ReadFile(string file)工具函数:读文件为 blob
boolean WriteFile(blob data, string file)工具函数:把 blob 写成文件


最关键的一点:Add* 之后必须调用 Close() 才会真正生成文件;中途想放弃调用 Discard()。这和数据库的事务提交/回滚是一个道理。

三、uo_zip 压缩:把目录和文件打进 ZIP


前置:工程已加入 websuite.pbl 并随应用分发 PbIdea.dll;下面代码放在某个按钮的 clicked 事件里,把路径换成你本机真实存在的目录/文件即可直接运行。



// 示例输入:要生成的 zip 文件完整路径(不存在会被创建)
string ls_zip
ls_zip = 'D:/temp/demo.zip'
// 示例输入:要加入压缩包的单文件完整路径
string ls_file
ls_file = 'D:/temp/report.txt'
// 示例输入:要整目录打包的源目录(含子目录一并保留)
string ls_srcdir
ls_srcdir = 'D:/temp/sourcedir'

uo_zip lz
lz = create uo_zip

// 打开压缩包(无密码);返回 true 表示打开成功
boolean lb_open
lb_open = lz.Open(ls_zip)
// 加入单个文件
lz.Add(ls_file)
// 加入整个目录,目录结构会被保留进压缩包
lz.AddPath(ls_srcdir)
// 只有 Close 才真正把数据写入磁盘(相当于 commit)
lz.Close()

destroy lz
MessageBox('压缩完成', '已生成:' + ls_zip)


如果要做加密 zip,把 Open 换成带密码的重载即可:


// 示例输入:zip 输出路径
string ls_zip
ls_zip = 'D:/temp/secret.zip'
// 示例输入:压缩密码
string ls_pwd
ls_pwd = 'MyPass123'

uo_zip lz
lz = create uo_zip

// bReadOnly=false 表示创建;第三个参数传密码即生成加密包
lz.Open(ls_zip, false, ls_pwd)
lz.Add('D:/temp/report.txt')
lz.Close()

destroy lz
MessageBox('加密压缩完成', ls_zip)


四、uo_zip 实战:解压与读取条目


前置:目标 zip 已存在(上面生成的 D:/temp/demo.zip),运行下面代码即可解压到指定目录。



// 示例输入:要解压的 zip 文件
string ls_zip
ls_zip = 'D:/temp/demo.zip'
// 示例输入:解压目标目录(不存在会自动创建)
string ls_out
ls_out = 'D:/temp/extract'

uo_zip lz
lz = create uo_zip

lz.Open(ls_zip)
// 解压全部条目到目标目录,返回解压出的条目数
long ll_n
ll_n = lz.Extract(ls_out)
lz.Close()

destroy lz
MessageBox('解压完成', '共解压 ' + string(ll_n) + ' 个条目')


读加密包时,Open 用只读 + 密码重载:lz.Open(ls_zip, true, ls_pwd)。

读取条目清单(不解压也能知道里面有什么):


// 示例输入:要查看的 zip 文件
string ls_zip
ls_zip = 'D:/temp/demo.zip'

uo_zip lz
lz = create uo_zip

lz.Open(ls_zip)

// GetEntryList 通过 ref 数组回填:索引/名称/原始大小/压缩后大小/CRC/时间/是否加密
long ll_index[]
string ls_name[]
long ll_size[]
long ll_sizecom[]
string ls_crc[]
string ls_dt[]
boolean lb_enc[]

long ll_cnt
ll_cnt = lz.GetEntryList(ll_index, ls_name, ll_size, ll_sizecom, ls_crc, ls_dt, lb_enc)

lz.Close()
destroy lz

MessageBox('条目数', string(ll_cnt))


只读取某个条目内容为 blob(常用于"从压缩包里取一张图/一份配置,不落盘"):


// 示例输入:zip 内要读取的条目名
string ls_name
ls_name = 'report.txt'
// 示例输入:zip 文件
string ls_zip
ls_zip = 'D:/temp/demo.zip'

uo_zip lz
lz = create uo_zip

lz.Open(ls_zip)
// 按名称读取为 blob;也可按索引:lz.ReadBlob(1)
blob lb_data
lb_data = lz.ReadBlob(ls_name)
lz.Close()
destroy lz

MessageBox('读到的字节数', string(len(lb_data)))


五、uo_zip 内存压缩:不落盘,直接打包 blob

有时根本没有物理文件——比如你在内存里拼好了一段 JSON、一段日志,想直接压成 zip 再通过网络发出去。用 Add(string 名称, blob 数据) 即可,无需任何物理文件:


// 示例输入:要打包进 zip 的文本内容
string ls_text
ls_text = 'Hello PBIDEA,这是内存压缩示例'
// 示例输入:zip 输出文件
string ls_zip
ls_zip = 'D:/temp/mem.zip'

uo_zip lz
lz = create uo_zip

lz.Open(ls_zip)
// 把字符串转 blob 后作为条目加入(条目名自定义为 memo.txt)
blob lb_blob
lb_blob = blob(ls_text)
lz.Add('memo.txt', lb_blob)
lz.Close()
destroy lz

MessageBox('内存压缩完成', ls_zip)


注意:blob(字符串) 按默认编码转换,若内容含中文且需 UTF-8,请先用 toUtf8(全局函数)转好再 blob()。

六、uo_7z 完整 API 清单

uo_7z 对外方法(均来自 PbIdea.dll 的 SevenZip* 系列):


方法说明
boolean AddDir(string strDir)加入整个目录(默认含子目录)
boolean AddDir(string, boolean includeSubDir)是否含子目录
boolean AddDir(string, string strFilter, boolean includeSubDir)指定文件过滤(如 *.txt)
boolean AddFile(string fileName)加入单个文件
boolean Compress(string str7zFile)开始压缩成 .7z
boolean Compress(string str7zFile, boolean showProgress)压缩并显示进度条
boolean Extract(string str7zFile, string strDir)解压到目录
boolean Extract(string str7zFile, string strDir, boolean showProgress)解压并显示进度条
blob Compress7Z(blob data)内存 7z 压缩(自定义格式)
blob Uncompress7Z(blob data)内存 7z 解压(须配对使用)


和 uo_zip 不同,uo_7z 没有显式的 Open/Close:先 AddDir / AddFile 累加内容,再 Compress 一次性产出;解压则直接 Extract(源文件, 目标目录)。

七、uo_7z 压缩目录/文件为 .7z


前置:同前,把路径换成你本机真实目录即可运行。



// 示例输入:要生成的 7z 文件
string ls_7z
ls_7z = 'D:/temp/demo.7z'
// 示例输入:要压缩的目录(含子目录)
string ls_dir
ls_dir = 'D:/temp/sourcedir'
// 示例输入:是否弹出进度条
boolean lb_progress
lb_progress = false

uo_7z l7
l7 = create uo_7z

// 加入整个目录(含子目录)
l7.AddDir(ls_dir)
// 也可追加单个文件:l7.AddFile('D:/temp/a.txt')
// 仅压特定类型:l7.AddDir(ls_dir, '*.txt', true)
boolean lb_ok
lb_ok = l7.Compress(ls_7z, lb_progress)
destroy l7

MessageBox('7z 压缩结果', string(lb_ok))


八、uo_7z 解压 .7z


// 示例输入:源 7z 文件
string ls_7z
ls_7z = 'D:/temp/demo.7z'
// 示例输入:解压目标目录
string ls_out
ls_out = 'D:/temp/extract7z'

uo_7z l7
l7 = create uo_7z

boolean lb_ok
lb_ok = l7.Extract(ls_7z, ls_out)
destroy l7

MessageBox('7z 解压结果', string(lb_ok))


九、uo_7z 内存 7z 压缩(blob,自定义格式)

Compress7Z / Uncompress7Z 走的是 7z 内核的自定义内存格式,适合把一段二进制数据压小后存库或走网络,但只能用 Uncompress7Z 还原,标准 7z 工具打不开这段 blob——这点务必记牢。


// 示例输入:要压缩的二进制数据(这里用字符串转 blob 示意)
blob lb_src
lb_src = blob('PBIDEA 7z 内存压缩示例内容')
// 若是读真实文件:lb_src = lz.ReadFile('D:/temp/big.dat')

uo_7z l7
l7 = create uo_7z

// 压缩
blob lb_cmp
lb_cmp = l7.Compress7Z(lb_src)
// 解压还原(必须配对使用)
blob lb_dec
lb_dec = l7.Uncompress7Z(lb_cmp)
destroy l7

MessageBox('压缩前后字节数', string(len(lb_src)) + ' -> ' + string(len(lb_cmp)))


十、进阶:配合 uo_dir 做选择性遍历再压缩

uo_zip.AddPath 是"整目录无脑打包"。如果你想按条件挑选文件(比如只压最近修改的、或只压某扩展名),可以先用 uo_dir(它是 autoinstantiate,无需 create)枚举文件清单,再逐一对 uo_zip 的 Add 调用。


// 示例输入:要遍历的目录
string ls_dir
ls_dir = 'D:/temp/sourcedir'
// 示例输入:文件名过滤(* 表示全部)
string ls_filter
ls_filter = '*.txt'
// 示例输入:zip 输出路径
string ls_zip
ls_zip = 'D:/temp/selected.zip'

uo_dir ld
// uo_dir 为 autoinstantiate,无需 create
string ls_files[]
long ll_cnt
ll_cnt = ld.files(ls_dir, ls_filter, ls_files)

uo_zip lz
lz = create uo_zip
lz.Open(ls_zip)

long i
for i = 1 to ll_cnt
    // 对每个命中的文件加入压缩包(这里直接用其完整路径作为条目名)
    lz.Add(ls_files)
next

lz.Close()
destroy lz

MessageBox('已挑选并压缩的文件数', string(ll_cnt))


uo_dir 常用配套:md(dir) 建多级目录、exist(file) 判断存在、dirs(dir, ref) 列子目录、del(file) 删文件、GetSize(dir) 算目录大小,均可直接调用。

边界情况与常见坑


[*]忘了 Close() 导致文件没生成:uo_zip 的所有 Add* 都只是"暂存",只有 Close() 才真正写盘;出错想放弃用 Discard()。这是最高频的坑。
[*]uo_zip / uo_7z 必须 create/destroy:两者 constructor/destructor 里分别调用了 zipCreate/zipDestroy 与 SevenZipCreate/SevenZipDestroy,不 create 会报空对象,不 destroy 会泄漏底层句柄。
[*]7z 内存压缩的 blob 不能用标准工具解:Compress7Z 产出的是自定义格式,归档给别人的 7z 请用 Compress(文件) 走标准 .7z;内存 blob 仅限自己 Uncompress7Z 还原。
[*]GetEntryList 的 ref 数组要预先声明:七个 ref 数组(index/name/size/sizecom/crc/dt/enc)都要先声明再传入,函数通过引用回填,返回值是条目总数。
[*]中文路径/密码:底层走系统 API,建议路径与密码尽量使用 ASCII;中文文件名一般可行,但跨机器交换时优先用英文文件名最稳妥。
[*]Open(blob, 密码) 只读打开:这个重载只能读不能写,用来"从一段内存里的 zip 数据直接读取条目"很方便,但别指望再往里 Add。
[*]PbIdea.dll 必须随应用分发:这两个对象都依赖 PbIdea.dll,开发机能跑不代表客户机能跑,部署时务必把 dll 一起带上。


ZIP 还是 7z?以及替代方案


[*]兼容性优先 → uo_zip(ZIP):ZIP 是事实标准,Windows 资源管理器、各类解压软件原生支持,客户拿到就能双击打开,适合对外分发的附件、更新包。
[*]压缩率优先 → uo_7z(7z):7z 对大量小文件、文本类数据通常压得更小,适合内部归档、备份传输;但对方需要 7-Zip 或支持 7z 的工具才能解。
[*]纯内存数据压小 → 两者都行:uo_zip 的 Add(名称, blob) + 不解压直接用 ReadBlob;uo_7z 的 Compress7Z/Uncompress7Z(注意自定义格式)。
[*]替代方案:若只要最简单且不想依赖 PbIdea.dll,可用 Run 调用系统/第三方的 7z.exe、tar.exe;但那样要处理命令行、等待进程、解析返回,远不如这两个对象来得干净、可控。PBIDEA 没有内置 rar 对象,需要 rar 格式时仍建议走外部 exe 或改用 zip/7z。


小结

在 PB 里做压缩解压,记住三件事就够用了:uo_zip 管 ZIP(Open→Add→Close 三段式,别忘了 Close)、uo_7z 管 7z(AddDir/AddFile→Compress,Extract 直接解)、两者都靠 PbIdea.dll 且都要 create/destroy。需要挑文件就用 uo_dir 先枚举再 Add。把这几段代码收进你的工具库,以后导出、归档、打包上传都能直接复用。
页: [1]
查看完整版本: PBIDEA:用 uo_zip 与 uo_7z 在 PowerBuilder 里做 ZIP 与 7z 压缩解压

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

Mail To:Admin@SybaseBbs.com