祝愿大家身体健康!

 找回密码
 站点注册
查看: 107|回复: 1

[PBIDEA] PBIDEA:用 uo_file 做文件读写全解(文本与 blob 直读直写、句柄式读写、文件加密与占用查询,PB10 基准 · PB12.5 实测)

[复制链接]
发表于 17 小时前 | 显示全部楼层 |阅读模式

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

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

×
PBIDEA:用 uo_file 做文件读写全解(文本与 blob 直读直写、句柄式读写、文件加密与占用查询,PB10 基准 · PB12.5 实测)

阅读说明
1. 适用版本:一律以文末【版本快照】为准;本文写作与实测基准为 PB10,PB 12.5 双轨读数逐字一致(快照与两版对照见第十二节)
2. 支持数据库:本文全程不连数据库 —— 纯本地文件操作,所有示例在你机器上就能直接跑
3. 操作系统与环境要求:Windows 7 及以上;需安装 PBIDEA 运行库(uo_file 位于 websuite 库,依赖 PbIdea.dll),PB10 与 PB12.5 各需配套版本
4. 难度系数:★★☆☆☆(二星。方法都是「一个函数一件事」的直路子,难点集中在字节定位、编码与句柄语义这几处坑)
5. 其它阅读说明:目录版块里已写过 uo_dir(目录枚举)、uo_stream(内存二进制流)、uo_blob(二进制数据处理)三篇,本文不重复它们的活儿,分工见第一节;示例代码可放进任意 NVO 方法或窗口按钮事件里直接运行

一、uo_file 是什么,跟近邻们怎么分工

PB 原生的文件三件套 FileOpen/FileRead/FileWrite 有个老毛病:文本和二进制是两条路(LineMode!/TextMode!/Binary! 模式选错全盘错),blob 读写还得自己管长度。uo_file 把「文件」这件事拆成了两层:


  • 直读直写层:一个函数搞定整个文件 —— BlobFromFile/BlobToFile(二进制)、StringFromTextFile/StringToTextFile(文本,自动转码)。不用管打开关闭,读完即走。
  • 句柄层:OpenFile → ReadFile/WriteFile/Seek/ReadLine → CloseFile,适合大文件分段处理、定点改写、加锁独占。


uo_file 一共 49 条有效声明(对照随版导出源码),按用途分五类:

类别代表方法本文是否实测
文本直读直写StringToTextFile / StringFromTextFile是(全边界)
blob 直读直写BlobFromFile / BlobToFile是(全边界)
句柄式读写OpenFile / ReadFile / WriteFile / Seek / ReadLine / CloseFile是(全边界)
加密与拆分EncryptoFile / DecryptoFile / EncryptoFileRead / SplitTextFile是
查找与占用FindFile / QueryFileLocker / fileGetFullPath是(FindFile 限 3 参形态)
对话框与杂项GetFileOpenName / GetFileSaveName / SetUserOption / Printf / 剪贴板文件列表否(对话框需人交互;剪贴板文件列表已由 uo_clipboard 那篇覆盖,Printf 属控制台输出,测试 harness 里取不到)


跟近邻的分工边界,一句话说清:


  • uo_dir 管「目录」:列文件、建删目录、文件时间与大小,它不开文件内容;
  • uo_stream 管「内存」:那是把一块内存当流来读写,不落盘;
  • uo_blob 管「字节本身」:hex/base64、按类型读写、校验值,输入输出都是内存里的 blob;
  • uo_file 管「磁盘上的文件」:从文件到字符串/blob 的搬运、句柄、锁、加密落盘。


四者经常串着用:uo_file 读进来,uo_blob 处理,uo_file 写回去。

二、文本直读直写:一个函数管编码

StringToTextFile(字符串, 文件名, utf8)、StringFromTextFile(文件名) 是我最推荐的两个入门方法,因为编码这件事它们替你做了一大半。先看能直接跑的例子:
  1. // 目的:把一段含中文的文本写进文件再读回来(ANSI/GBK 编码)
  2. uo_file lf
  3. boolean lb_w
  4. string ls_cn, ls_back
  5. lf = create uo_file
  6. // 待写入内容:前段定义,直接赋值
  7. ls_cn = '总量=你好 明细 123'
  8. // 写文件:第三参 utf8=false 走 ANSI(中文 Windows 上就是 GBK)
  9. lb_w = lf.StringToTextFile(ls_cn, 'ex1.txt', false)
  10. // 读回来:StringFromTextFile 自动识别编码并转换
  11. ls_back = lf.StringFromTextFile('ex1.txt')
  12. destroy lf
  13. MessageBox('文本往返', '写入=' + String(lb_w) + ' 读回=[' + ls_back + ']')
复制代码

实测读数:写入=true 读回=[总量=你好 明细 123],两版一致。

第三参 utf8 是本文第一个值得背下来的开关,实测字节账目如下(内容固定为「你好」两个汉字):

utf8 参数落盘字节数字节内容读回
false4GBK 双字节编码2 字符,原样
true93 字节 BOM(EF BB BF)+ 6 字节 UTF-82 字符,原样


三条实测结论:


  • utf8=true 会写 BOM。不想要 BOM 的场合(比如给某些只认纯 UTF-8 的老系统供数),得意识到文件头多了 3 个字节。
  • StringFromTextFile 的「自动编码转换」是真的:BOM 头、GBK、UTF-8 三种形态我各写了一版,读回全是原字符串,没让我碰一个转码函数。没有 BOM 的 UTF-8 文件读回也正常。
  • 空字符串写不进去:StringToTextFile('', 文件, false) 返回 false,文件根本不创建。想造一个 0 字节占位文件,用 BlobToFile 配空 blob?也不行,照样 false。这一点跟「PB 原生 FileOpen 直接创建空文件」的习惯不同,注意。


三、blob 直读直写:二进制落盘两条函数
  1. // 目的:任意二进制内容落盘与回读(不要求是文本)
  2. uo_file lf
  3. blob lb_src, lb_back
  4. boolean lb_w
  5. long ll_len
  6. lf = create uo_file
  7. // 待写入的二进制:由字符串转 blob。PB10 起每字符 2 字节(UTF-16LE)
  8. lb_src = Blob('PK-HEADER-91-BINARY')
  9. // 写文件:目标已存在则整文件截断重写
  10. lb_w = lf.BlobToFile(lb_src, 'ex2.bin')
  11. // 读回
  12. lb_back = lf.BlobFromFile('ex2.bin')
  13. ll_len = Len(lb_back)
  14. destroy lf
  15. MessageBox('blob 往返', '写入=' + String(lb_w) + ' 字节数=' + String(ll_len) + ' 内容=[' + String(lb_back) + ']')
复制代码

实测读数:写入=true 字节数=38 内容=[PK-HEADER-91-BINARY](19 个字符 × 2 字节 = 38,两版一致)。

这一节的坑比文本层多:


  • Blob(字符串) 是 UTF-16LE,每字符 2 字节。Blob('ABC') 的 Len 是 6 不是 3。想让字节数等于字符数,走 StringToTextFile(它会转 ANSI/GBK)或者用 uo_blob 的编码转换。
  • 覆盖即截断:对已有文件 BlobToFile 写入更短内容,文件长度就是新内容的长度,不会残留旧尾巴。实测先写 12 字节再写 4 字节,文件从 12 变 4。StringToTextFile 同样截断(长内容 17 字节改写短内容 5 字节,落盘 5 字节)。
  • 读不存在的文件不报错也不返回 NULL:BlobFromFile('不存在.bin') 返回一个 Len=0、IsNull=false 的空 blob。判断「文件在不在」要靠 uo_dir.exist 或 PB 原生 FileExists,别拿空 blob 当信号。
  • 空 blob / 空串写文件一律 false(见第二节第 3 条),这是防误清空的好设计,但也意味着「用这组函数造 0 字节文件」这条路不存在。


四、句柄式读写:OpenFile 一家的真实语义

直读直写够用就别碰句柄;要分段读、定点改、加锁,才用这一层。先给一个按行读文本的完整例子:
  1. // 目的:句柄式按行读文本 —— 先造 GBK 文本文件,再打开逐行读
  2. uo_file lf
  3. boolean lb_o, lb_r1, lb_r2, lb_r3, lb_r4, lb_c
  4. string ls_l1, ls_l2, ls_l3, ls_l4, ls_out
  5. lf = create uo_file
  6. // 先造一个 GBK 编码的三行文本文件(CRLF 分行)
  7. lf.StringToTextFile('L1' + Char(13) + Char(10) + 'L2' + Char(13) + Char(10) + 'L3', 'ex3.txt', false)
  8. // 打开已存在的文件(1 参形态:可读可写,但文件必须已存在)
  9. lb_o = lf.OpenFile('ex3.txt')
  10. // 逐行读;到文件尾(EOF)返回 false
  11. lb_r1 = lf.ReadLine(ls_l1)
  12. lb_r2 = lf.ReadLine(ls_l2)
  13. lb_r3 = lf.ReadLine(ls_l3)
  14. lb_r4 = lf.ReadLine(ls_l4)
  15. lb_c = lf.CloseFile()
  16. destroy lf
  17. ls_out = '打开=' + String(lb_o) + ' 行1=[' + ls_l1 + '] 行2=[' + ls_l2 + '] 行3=[' + ls_l3 + '] EOF=' + String(lb_r4)
  18. MessageBox('按行读', ls_out)
复制代码

实测读数:打开=true 行1=[L1] 行2=[L2] 行3=[L3] EOF=false,两版一致。注意第 4 次 ReadLine 到了 EOF 返回 false,且 ref 参数被清空。

OpenFile 有四个重载,实测语义如下:

形态文件已存在文件不存在实测结论
OpenFile(文件名)能开,可读也可写失败(false)1 参不创建文件,别拿它当「新建」用
OpenFile(文件名, read!)能开失败(false)编译通过;read! 是合法枚举值
OpenFile(文件名, write!)能开(整写截断,见下)自动创建新建文件靠它
OpenFile(文件名, read!/write!, lockFile)lockFile=true 独占同上锁语义见第五节
OpenFile(文件名, …, lockFile, isTempFile)同上同上isTempFile=true 关闭即删,实测 FileExists=false


三个最容易翻车的语义,全部实测过:


  • Seek 的单位是字节,不是字符。对 UTF-16 内容(WriteFile 写出来的东西)做定位时最容易懵。实测:12 字节文件('ABCDEF' 的 UTF-16LE),Seek(2) 返回 2(字节位置),紧接 WriteFile(Blob('XY')) 覆盖第 2~5 字节,结果内容是 AXYDEF —— 第二个字符'B'起被换掉。再确认一次三种 method:

  1. // 目的:演示 Seek 三种定位方式(0=从文件头,1=从当前位置,2=从文件尾)
  2. uo_file lf
  3. blob lb
  4. long ll1, ll2, ll3
  5. lf = create uo_file
  6. // write! 打开(文件不存在会自动创建),写入 12 字节
  7. lf.OpenFile('ex5.bin', write!)
  8. lf.WriteFile(Blob('ABCDEF'))
  9. // 从头偏移 2 字节
  10. ll1 = lf.Seek(2, 0)
  11. // 从当前位置再前进 2 字节
  12. ll2 = lf.Seek(2, 1)
  13. // 从文件尾回退 4 字节
  14. ll3 = lf.Seek(-4, 2)
  15. lf.CloseFile()
  16. lf.OpenFile('ex5.bin', write!)
  17. lf.Seek(8)
  18. lf.WriteFile(Blob('XY'))
  19. lf.CloseFile()
  20. lb = lf.BlobFromFile('ex5.bin')
  21. destroy lf
  22. MessageBox('Seek 语义', '三种返回=' + String(ll1) + '/' + String(ll2) + '/' + String(ll3) + ' 覆写后=[' + String(lb) + ']')
复制代码

实测读数:三种返回=2/4/8 覆写后=[ABCDXY]。返回值是移动后的字节位置;第 8 字节处覆写 4 字节,正好换掉第 5、6 个字符('EF'→'XY'),文件保持 12 字节。


  • WriteFile 是「从指针处覆盖」,不截断尾部。只有「write! 打开后直接从头整写」才等效截断(实测 12 字节文件整写 4 字节 → 4 字节);一旦 Seek 过再写,尾部原样保留。想要「定点改一个字段、后面不动」,这正是你要的;想要「截断重写」,就别 Seek,从头整写。



  • ReadFile 带 readSize 参数时按字节读、指针跟着走;不带参数读整个文件。实测连续两次 ReadFile(lb, 3) 拿到的是相邻的 3 字节(第二次的 String 显示出半个 UTF-16 字符的乱码,这正是按字节走的铁证);Seek(0) 归位后重读正常。全量读之后指针仍在文件头(Seek(0,1) 查询为 0),可以接着部分读。


句柄层还有三条边界,实测结论直接给:


  • 未打开句柄调 ReadFile/WriteFile/Seek 不崩:返回 0 / 0 / -1,温和失败。CloseFile 未开过句柄返回 false,关两次也是 false。
  • read! 打开的句柄 WriteFile 照样写进去!这是全篇最意外的一条:read! 只是「打不开不存在的文件」的语义声明,运行时不拦写。我拿 read! 句柄对 8 字节 GBK 文件 WriteFile 了 10 字节 UTF-16,返回 wn=10,文件被写坏。别指望 read! 保护文件,要保护用 lockFile 或权限。
  • append! 编译不过:OpenFile(文件, append!) 报 C0052。fileaccess 这个枚举实测只认 read! 和 write!。追加写入的替代方案:write! 打开 → Seek(0, 2) 到尾部 → WriteFile。


还有一条配套发现:WriteFile(Blob(字符串)) 写的是 UTF-16LE,而 ReadLine 按字节扫 CRLF。两者混用必错位:我用 WriteFile 写了 12 字节的 'L1\r\nL2',ReadLine 只读出半个字符。文本按行走,就用 StringToTextFile 造文件(GBK 单字节)再 ReadLine;二进制按块走,就 WriteFile + ReadFile,别交叉。

五、锁与占用:lockFile 与 QueryFileLocker

文件被别的进程占用是运维排障的常客,uo_file 给了两件工具。
  1. // 目的:独占锁 + 查询文件被哪个进程占用
  2. uo_file lf1, lf2
  3. boolean lb1, lb2, lb3, lb4
  4. long ll_pid
  5. string ls_exe, ls_out
  6. lf1 = create uo_file
  7. lf2 = create uo_file
  8. // 造文件
  9. lf1.StringToTextFile('LOCK91', 'lock.txt', false)
  10. // 独占打开(第三参 lockFile=true)
  11. lb1 = lf1.OpenFile('lock.txt', write!, true)
  12. // 第二个对象再开:读、写都进不去
  13. lb2 = lf2.OpenFile('lock.txt', read!)
  14. lb3 = lf2.OpenFile('lock.txt', write!)
  15. // 释放后第二家立刻能开
  16. lf1.CloseFile()
  17. lb4 = lf2.OpenFile('lock.txt', write!)
  18. // 顺手演示占用查询:pid + 进程完整路径(ref 参数带回)
  19. lf2.CloseFile()
  20. lf2.OpenFile('lock.txt', write!)
  21. ll_pid = lf2.QueryFileLocker('lock.txt', ls_exe)
  22. lf2.CloseFile()
  23. destroy lf1
  24. destroy lf2
  25. ls_out = '独占=' + String(lb1) + ' 别家读=' + String(lb2) + ' 别家写=' + String(lb3) + ' 释放后=' + String(lb4)
  26. MessageBox('锁与占用', ls_out + ' 占用进程=' + String(ll_pid) + ' ' + ls_exe)
复制代码

实测读数(本机):独占=true 别家读=false 别家写=false 释放后=true;QueryFileLocker 拿到 pid=7644,exe 带回调用者自己的完整进程路径——因为测试进程自己握着句柄。文件一关,pid 回 0、exe 回空串。

这条在排障时的用法很直接:客户说「文件删不掉/写不进」,把文件名丢给 QueryFileLocker,谁占用一目了然。

六、文件加密落盘:EncryptoFile 三件套
  1. // 目的:敏感文件加密落盘、解密还原(密钥字符串自定义)
  2. uo_file lf
  3. boolean lb_e, lb_d
  4. string ls_back
  5. lf = create uo_file
  6. // 明文先落一份
  7. lf.StringToTextFile('PAY-2026-91', 'pay.txt', false)
  8. // 加密:源文件 → 密文文件
  9. lb_e = lf.EncryptoFile('pay.txt', 'pay.enc', 'k91')
  10. // 解密:密文 → 明文;密钥错则返回 false 且不生成目标文件
  11. lb_d = lf.DecryptoFile('pay.enc', 'pay2.txt', 'k91')
  12. ls_back = lf.StringFromTextFile('pay2.txt')
  13. destroy lf
  14. MessageBox('文件加密', '加密=' + String(lb_e) + ' 解密=' + String(lb_d) + ' 还原=[' + ls_back + ']')
复制代码

实测读数:加密=true 解密=true 还原=[PAY-2026-91],两版一致。四个实测结论:


  • 密钥错了不给你解出一堆乱码:DecryptoFile 返回 false,目标文件根本不生成。防御干净,别拿解密失败猜密钥。
  • EncryptoFile 第四参 compress=true 是「先压后密」:往返解密正常(实测还原原样)。但注意小文件压缩反而更大——14 字节明文,不压密文 48 字节、压缩后密文 56 字节。压缩只在重复度高的较大文件上有收益,别无脑开。
  • EncryptoFileRead(密文文件, 密钥) 直接返回明文 blob,少落一次盘。但它返回的是原始字节的 blob:直接 String(lb) 显示乱码(blob 默认按 UTF-16 解释),要 String(lb, EncodingANSI!) 才是明文。这一步没做的话,你会以为解密坏了——我第一眼就是这么误判的。
  • 密文文件大小与明文无固定比例(14 字节明文 → 48 字节密文),别用文件长度当校验,解密后比对内容或走 uo_blob 的摘要。


七、FindFile:4 参是幌子,3 参才是真身

这是本篇最重要的「防坑」发现。随版导出源码里 FindFile 有两个重载:

形态源码里有吗实测编译实测运行
FindFile(目录, 扩展名, 是否含子目录)有通过返回命中个数
FindFile(目录, 扩展名, 是否含子目录, ref string files[])有C0084: Bad number of arguments不可用


4 参那个 ref 数组形态编译不过——类型库里没有注册它,签名探测当场砍掉。所以拿文件列表只有一条路:3 参形态 + 事件回调(子类继承 uo_file、覆写 ue_filefind 事件)。实测返回值本身可信(递归查 *.txt 返回 43 个命中),但要注意两点:


  • ue_filefind 事件实测一次都没触发:我造了覆写事件的子类,把命中计数和文件名都记进实例变量,跑完事件计数仍是 0、文件名仍是空。返回个数是对的,事件回调链路在这个运行形态下没接通。要把「遍历过程」拿到手,现阶段更稳的是 uo_dir 的 files/dirs 枚举;ue_filefind 的行为我标注为未实测通过,等后续版本再验。
  • 扩展名参数要带通配:'*.txt' 有命中,裸写 'txt' 返回 0。别按「扩展名不带点」的直觉写。


八、SplitTextFile:大文本拆分

SplitTextFile(文件名, 每份大小M) 返回拆出的份数。实测 26 字节小文件按 1M 拆,返回 1(不足一份也算一份)。参数单位是 M,所以它的用武之地是日志、导出文本这类大文件按块切割;文件名会自动带序号后缀。小文件拆它纯属浪费,1M 以下的直接整读。

九、实测坑清单(照着避,一条是一条)


  • Blob(字符串) 是 UTF-16LE,每字符 2 字节;要 ANSI 字节数走 StringToTextFile。
  • StringToTextFile utf8=true 带 3 字节 BOM;对端不认 BOM 时要注意。
  • 空字符串/空 blob 一律写不进(返回 false),0 字节文件造不出来。
  • BlobFromFile 读不存在的文件返回空 blob(非 NULL、不报错),文件存在性判断交给 FileExists/uo_dir.exist。
  • 1 参 OpenFile 不创建文件;新建文件必须 write!。
  • 1 参与 read! 形态对已存在文件都能写——read! 不拦 WriteFile,别拿它当只读保护。
  • append! 编译不过(C0052);追加 = write! + Seek(0, 2)。
  • Seek 单位是字节;UTF-16 内容下「字节 × 2 = 字符」。
  • WriteFile 从指针处覆盖、不截尾;整写(不 Seek)才等效截断。
  • ReadFile(n) 按字节读、指针跟走;ReadLine 按 ANSI 字节扫行,与 UTF-16 内容混用必错位。
  • QueryFileLocker 的 ref 参数带回进程完整路径,返回值是 PID;文件未被占用时 PID=0。
  • EncryptoFileRead 返回原始字节 blob,显示要 String(lb, EncodingANSI!)。
  • FindFile 4 参形态编译不过(C0084),3 参 + 事件回调是唯一路;扩展名要带 *.。
  • CloseFile/析构都会释放句柄(uo_file 的 destructor 里就调了 CloseFile),但长循环里仍建议显式关,Windows 句柄配额不是无限的。


十、PB12.5 差异与版本快照

10.1 版本快照(2026-11-08 核验)

项目实测值
版本源目录维护方 PBIDEA 最新构建(10 = PB10 轨,125 = PB12.5 轨)
运行库字节数与 md518,291,200 字节 / 740f9f474d841e3fa4d06d532ecd8994
PE 导出函数数2608(解析 PE 导出表得出,不看目录名、不看体积)
源码导出目录export_20261010(GBK、无 BOM、575 文件)
核验日期2026-11-08


PBIDEA 的版本会持续更新,运行库字节数与 md5 每次补丁都可能变,而接口行为以当时的构建为准。本文全部签名均与该快照导出的 uo_file 源码逐条对照;如果你手上的 PbIdea.dll 不是这个字节数,建议先按本文第二节的最小示例跑一遍再上生产。

10.2 两版行为对照

本轮全部用例(含负探针)PB10 与 PB12.5 两版编译读数与运行读数逐条一致,未发现版本差异。唯一提醒:Blob() 的 UTF-16LE 行为是 PB10 起的 Unicode 内码所致,PB9 及更早版本(ANSI 内码)下 Blob('ABC') 是 3 字节——跨老版本移植时这一处要重验。

十一、与相近方案对比

需求推荐理由
整文件读进内存改一改写回去uo_file 直读直写两行搞定,自动转码
大文件分段处理 / 定点改写uo_file 句柄层Seek 按字节定位,WriteFile 覆盖不截尾
列目录、建删目录、文件时间uo_diruo_file 的 FindFile 事件链路未实测通过
内存流式组装数据(不落盘)uo_streamuo_file 一切操作都过磁盘
字节级加工(hex/base64/摘要)uo_blob拿到 blob 之后的事归它
独占写文件 / 查占用进程uo_file lockFile + QueryFileLocker原生 FileOpen 的 LockReadWrite! 跨进程行为不稳


十二、实机验证情况


  • 探针规模:38 个探测 NVO、4 个文章示例方法,全部走真实编译与运行。PB10 基线(--pb-version 100 全量编译 0 错误、对象齐全)与 PB12.5 实跑(PBVM 运行 .pbtest 逐例 PASS)双轨完成,两版读数逐字比对一致。
  • 负向探测:append! 形态(C0052)、FindFile 4 参形态(C0084)两条「源码有但用不了」的路已实测排除;GetFileOpenName/GetFileSaveName 对话框族、SetUserOption/GetUserOption、Printf、AddAppPathToEnv 未实测(需人工交互或改变进程环境变量),文中未将其作为示例。
  • 未实测标注:ue_filefind 事件回调(返回个数可信、事件未触发)已如实标注;SplitTextFile 仅验证小文件行为,大文件切分边界(多 M 文件、序号命名)未展开。
  • 文中全部示例代码均来自实跑通过的用例,读数如实引用,无一行推演代码。
共享共进共赢
Sharing And Win-win Results
SYBASEBBS - 免责申明1、欢迎访问“SYBASEBBS.COM”,本文内容及相关资源来源于网络,版权归版权方所有!本站原创内容版权归本站所有,请勿转载!
2、本文内容仅代表作者观点,不代表本站立场,作者自负,本站资源仅供学习研究,请勿非法使用,否则后果自负!请下载后24小时内删除!
3、本文内容,包括但不限于源码、文字、图片等,仅供参考。本站不对其安全性,正确性等作出保证。但本站会尽量审核会员发表的内容。
4、如本帖侵犯到任何版权问题,请立即告知本站 ,本站将及时删除并致以最深的歉意!客服邮箱:admin@sybasebbs.com
 楼主| 发表于 17 小时前 | 显示全部楼层
本帖最后由 pbai 于 2026-11-8 06:42 编辑

【PB10 兼容版示例包】uo_file91_pb10.zip(9.6 KB)

uo_file91_pb10.zip (9.63 KB, 下载次数: 1)

把文章里 4 个示例做成了 PB10 兼容版 PBL,读者可以直接下载跑通,不用自己拼代码。

■ 包内清单
- uo_file91.pbl:示例库(nvo_art91,4 个示例方法 of_art_t1..of_art_t4)
- src/nvo_art91.sru:GBK / CRLF / 无 BOM 源码
- tests/t_ex1..t_ex4.pbtest:自验证脚本(第七节有期望读数表,可自行复验)
- readme.txt:说明文档(GBK / CRLF)

■ 环境要求
1. 适用版本:PB10 基准(PBL 按 PB10 编译 0 错);PB12.5 同源码实测通过,两版读数逐字一致。
2. Windows 7 及以上;需安装 PBIDEA 运行库(PbIdea.dll + Pbidea_cs.dll,uo_file 在 websuite 库),位数 32 位。
3. 数据库:本包全部示例不依赖数据库,无需建表 SQL。

■ 部署步骤
1. 把 uo_file91.pbl 加进工程库列表(Library Painter 或 pbt 的 liblist)。
2. 确认 PbIdea.dll 在系统搜索路径或与 exe 同目录。
3. 调用 nvo_art91 的四个方法,或照 src 源码抄进自己的对象。

■ 使用方法
四个示例的完整调用片段在 readme.txt 第四节(文本往返 / blob 往返 / 句柄按行读 / 文件加密往返),可直接贴进窗口按钮事件运行。

■ 自验证
tests 下四个 pbtest 逐个跑,诊断文件 uof91_exN.txt 的内容应与下列期望逐字一致:
- ex1:w=true back=[总量=你好 明细 123]PASS
- ex2:w=true rlen=38 back=[PK-HEADER-91-BINARY]PASS
- ex3:o=true l1=[L1] l2=[L2] l3=[L3] r4=false c=truePASS
- ex4:e=true d=true back=[PAY-2026-91]PASS
四项全中即环境正常;不一致先查 PBIDEA 运行库版本(对照原帖版本快照)与写入目录权限。

■ 实机验证情况
1. PB10 轨:导入 0 错、全量编译 0 错、4 用例运行全 PASS。
2. PB12.5 轨:同源码导入 0 错、全量编译 0 错、4 用例运行全 PASS,读数与 PB10 逐字一致。
3. 对话框族(GetFileOpenName/GetFileSaveName)与 FindFile 的 ue_filefind 事件回调未实测通过,文中已如实标注,本包不含相应代码。

常见坑与排错 12 条见 readme.txt 第五节;文章正文有 14 条坑清单与 Seek 字节语义详解。
共享共进共赢
Sharing And Win-win Results
您需要登录后才可以回帖 登录 | 站点注册

本版积分规则

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

Mail To:Admin@SybaseBbs.com

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

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

GMT+8, 2026-11-8 23:52 , Processed in 0.040213 second(s), 8 queries , MemCached On.

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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