再次寻求FPT文件变大的解决方案!

jsxhl 2005-10-28 11:55:25
原贴:
http://community.csdn.net/Expert/topic/4353/4353285.xml?temp=.350918

新的问题是,我程序的主要任务就是操作备注字段,把一文本文件内容进行处理并分离追加至数据表的相应备注字段中去。有时当遇见较大文本文件时,得分离追加上万次。追加命令用的是

REPL 备注字段 WITH 备注字段+分离的文本

这就带来问题:如果每次都用PACK MEMO 进行减肥,则明显不是优化的代码,再者也影响运行速度,如果我每追加一百次时就PACK一次,我发现在至一百次PACK前,FPT文件已变得上百兆,心里极不舒服。

从感觉上,事后减肥的方法不应是最佳方法,有没事前预防的方法?即无论我如何操作,FPT文件都只保持适当的大小,不会无限制的变大?FPT增大的空间到底是做什么用的?如果说是把备注字段中内容象普通记录打上删除标记进行备份一样,那如何能使此自动备份的功能失效?(即类似于使DELE命令直接彻底删除指定记录,不用打上标记)

版本XP+VFP6.0

期待中。。。。。
...全文
242 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
jsxhl 2005-11-03
  • 打赏
  • 举报
回复
楼上所说,对原始文本文件只遍历一次,又只需使用一个临时文本,就是我现在方法,且没有用临时文本,直接用表达式代替临时文本。

楼上不是没有理解我的原意就是我表达有误!

看来 zsjiaming(路口就在不远处)的方法是最佳方案了,结贴!
JohnShen 2005-11-01
  • 打赏
  • 举报
回复
"通常每次处理的文本文件都要涉及数据表中几十个记录,按楼上建临时文本的思路有两种方法:一是建几十个临时文本,以供不同数据表记录追加使用;二是只使用一个临时文本,对原始待分离的文本从头到尾梳理几十次,一次解决一个相关数据表记录。"

嗯?难道不能对原始文本文件只遍历一次,又只需使用一个临时文本吗?
jsxhl 2005-11-01
  • 打赏
  • 举报
回复
这个问题难道让它就这样不明不白的沉底么?
aabiao 2005-11-01
  • 打赏
  • 举报
回复
楼上正解!
zsjiaming 2005-11-01
  • 打赏
  • 举报
回复
今天花时间验证了一下.发现:
(1)ftp的增大和你建立这个DBF时设置的备注字段的磁盘空间的块儿的大小有关.
(2)ftp的增大和你replace 中串的大小有关,也和你执行replace的次数有关.

具体来说:
假设你建立表时定义备注字段的磁盘空间的块儿的大小是bsize
而你旧的备注内容为oldmemo ,要更新成的新的备注内容为newmemo
(1) 当newmemo的大小<=oldmemo时
因为新的内容在原来分配的块内可以放的下,所以不会再分配空间
备注文件不增大

(2) 当newmemo的大小>oldmemo时分二种情况
(ceiling取大于或等于指定数值表达式的最小整数)
新的内容所要分配的块数new_b_count
new_b_count= CEILING(len(newmemo)/bsize)
旧的内容已经分配的块数old_b_count
old_b_count= ceiling(len(oldmemo)/bsize)
A.newmemo需要的块数 与oldmemo需要的块数相同时
因为在原分配空间可以放下新内容,不会重新分配块.
B.newmemo需要的块数 大于oldmemo需要的块数时,文件增大,
new_b_count>old_b_count时,
因为原来分配空间装不下新内容,FPT文件会重新分配一个新的连续块给这个这字段,
但是......旧的块不删除..也不会被使用......>这二点是关键.
所以你的文件增大的比你预想的还要大
这时总分配空间是: new_b_count*bsize + old_b_count*bsize
多增加的是 old_b_count *bsize

当然对于没用使用的块你可用pack删除
(1)pack 删除dbf及fpt中不用的块(这个块不一定是执行了dele命令,就象前面
所说的,如果空间不足也会产生不用的块)
(2)pack memo 删除fpt中不用的块 (解释同上)

现在知道的文件增大的原理,相应的对策也就有了.
这时可能找不到一个最好的方法,而是找一个折中的方法.
1.默认的blocksize 是64 也就是新备注的内容比旧备注的内容增加超过64时,
就会产生一个新的分配空间.旧的空间不被使用及删除直到你执行PACK时.
2.如果定义的blocksize太大的话,又可能大部分空间都是空的.记录多时,文件增加也快.
3.如果太少,就会不断产生不用的旧块,文件增加也快.
那么你只能设定一个合理的blocksize....这个大小应该和你平均大小略大一些.
4.如果你的记录数不多,而更新的次数可能更多一些,那么blocksize要大一点,
5.如果记录多,而更新的次数少一点,你的块就可以定义的小一点.

另外说明,已经建立好的表,不能修改 备注字段块的大小,只有新建立时set blocksize才有作用.


附测试代码:

test =2
Set Blocksize To 5000
* 当blocksize为64.test=1时
* FPT文件大小为300多M
* pack 后 300多K
* 当blocksize为5000.test=1时
* FPT文件大小为4M多
* pack 后 200多K
*当test=2时,文件大小不变化.
*
Create Table F:\a111.Dbf Free (aa c(10), bb m(4))
Select a111
Append Blank
Replace a111.bb With Replicate("TESTA",1010)
For i=1 To 10000
Do Case
Case test==1
Replace a111.bb With a111.bb+Padl(Str(i),20)
Case test==2
Replace a111.bb With Replicate("testa",1010)
Endcase
Endfor


jsxhl 2005-10-29
  • 打赏
  • 举报
回复
首先谢谢楼上

我的程序是对文本中的内容进行辨别,这些文本有特殊的固定格式,由一小段一小段组成(每一小段就几行),一个大的文本可能达到几万行,程序的任务就是对每一小段进行分析,然后将每一小段分离出追加到数据表相应记录的备注字段当中去(每一小段在表中都能找到相应记录,如找不到则追加新的记录),表中记录通常达上千个。

所以,对楼上讲两个方法还是不适用我的程序。
十豆三 2005-10-29
  • 打赏
  • 举报
回复
有时当遇见较大文本文件时,得分离追加上万次。

*-------------------------------------------

为什么要分离,一次加就可以,即把你的

REPL 备注字段 WITH 备注字段+分离的文本
PACK MEMO
REPL 备注字段 WITH 备注字段+分离的文本
PACK MEMO
....

换成两句就可以了:

APPEND MEMO 备注字段 FROM 文本名.txt &&必须包含完整的文本文件名,包括扩展名。
PACK MEMO

这样代码多简洁呀
十豆三 2005-10-29
  • 打赏
  • 举报
回复
用如下方式试试:

APPEND MEMO 备注字段 FROM 文本名.txt

忽略参数 OVERWRITE,文本文件的全部内容将追加到当前记录的指定备注字段中。
jsxhl 2005-10-29
  • 打赏
  • 举报
回复
楼上加参数ADDITIVE的方法还是不行,如果不用PACK,FPT文件大小还是直线上窜。

看来还不是我理解的全盘替换造成的亢余空间。

十豆三 2005-10-29
  • 打赏
  • 举报
回复
再试试这样:

REPL 备注字段 WITH 备注字段+需追加的文本 ADDITIVE

即加个参数:ADDITIVE

ADDITIVE
把对备注字段的替代内容追加到备注字段的后面。ADDITIVE 只对替换备注字段有用。如果省略 ADDITIVE,则用表达式的值改写备注字段原有内容。
jsxhl 2005-10-29
  • 打赏
  • 举报
回复
其实我理解REPL命令是替换,即使我原先备注字段中内容很多,需加入的只是一小段,但用命令:

REPL 备注字段 WITH 备注字段+需追加的文本

却是将 原先的内容 + 需追加的文本 再全盘替换原先的备注内容,这个全盘替换可能就造成了大量的亢余空间,可否有真正的直接在原有基础上追加备注的命令?类似于:

APPEND MEMO 备注字段 FROM 文本名.txt

只不过要从表达式加入,而不是文件。
jsxhl 2005-10-29
  • 打赏
  • 举报
回复
每次追加备注字段都得重新寻找相应的记录,是同一条记录的概率比较小,属于您所说的“后者”。
十豆三 2005-10-29
  • 打赏
  • 举报
回复
引用:
“对原始文本从头按序读取小段落,按照读取的小段落去数据表中寻找相应记录(每个小段落对应数据表记录是无序的,由小段落中特定的标记决定),然后追加入备注字段中去”

---------------------------------

每次追加的备注字段是同一条记录吗?
如果是,就用我的方法,反之不能用我的方法。
十豆三 2005-10-29
  • 打赏
  • 举报
回复
我现在的方法是,对原始文本从头按序读取小段落,按照读取的小段落去数据表中寻找相应记录(每个小段落对应数据表记录是无序的,由小段落中特定的标记决定),然后追加入备注字段中去,

*--------------------------

“然后追加入备注字段中去”这个备注字段同一条记录,还是每次都不是一条。
如果是前者,那就用我的方法。
如果是后者,那就不用我的方法。
jsxhl 2005-10-29
  • 打赏
  • 举报
回复
通常每次处理的文本文件都要涉及数据表中几十个记录,按楼上建临时文本的思路有两种方法:一是建几十个临时文本,以供不同数据表记录追加使用;二是只使用一个临时文本,对原始待分离的文本从头到尾梳理几十次,一次解决一个相关数据表记录。

就我个人感觉,此两种方法不仅麻烦而且代码繁复,可否还有思路?

我现在的方法是,对原始文本从头按序读取小段落,按照读取的小段落去数据表中寻找相应记录(每个小段落对应数据表记录是无序的,由小段落中特定的标记决定),然后追加入备注字段中去,接着再读取下一小段文本内容,直至结束。 在此基础上加入中间环节,在代码的优化上是难以让人忍受的,速度也可能大受影响,比如,我曾尝试用编辑框作为中间过渡,但速度一下子降到了原先的十分之一以上!。
十豆三 2005-10-29
  • 打赏
  • 举报
回复
那就这样:
把文本分析截成小段先写入一临时文本文件(如TEMP.TXT)中,文本分析完成后再把这个临时文本追加到备注文件中。

例如:

IF FILE('TEMP.TXT') && 文件存在吗?
gnErrFile = FOPEN('TEMP.TXT',12) && 如果存在, 以读/写方式打开
ELSE
gnErrFile = FCREATE('TEMP.TXT') && 如果不存在, 创建它
ENDIF
IF gnErrFile < 0 && 检查打开文件错误
WAIT '不能打开或创建输出文件' WINDOW NOWAIT
=FCLOSE(gnErrFile) && 关闭文件
RETURN
ENDIF
&& 如果无错误, 写文件
DO WHILE .T. &&开始分隔你的文本,只需把此处按你的要求做一下修改
lStr=分离的文本
=FWRITE(gnErrFile, lStr) &&把分隔文本写入TEMP.TXT
ENDDO
=FCLOSE(gnErrFile) && 关闭文件

APPEND MEMO 备注字段 FROM TEMP.txt &&最后一次写入备注字段
PACK MEMO

2,722

社区成员

发帖
与我相关
我的任务
社区描述
VFP,是Microsoft公司推出的数据库开发软件,用它来开发数据库,既简单又方便。
社区管理员
  • VFP社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧