| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 7424 人关注过本帖, 1 人收藏
标题:发现1次EVALUATE()无法代替宏的,DBF转EXCEL
取消只看楼主 加入收藏
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:191
帖 子:3147
专家分:8408
注 册:2015-3-25
收藏
得分:0 
** 再次优化后
** CPU: I5 3470 ,WIN7 64系统,8G内存
** 设置格式时,20W条记录,用时 17秒,不设置格式时,用时16秒

** CPU: 酷睿双核 2.4 ,WIN7 32系统,4G内存
** 设置格式时,20W条记录,用时 45 秒,不设置格式时,用时51秒


CREATE CURSOR 测试表(入库单号 C(7),入库日期 D,物料名称 C(20),数量 I,单价 N(6,2),单位 C(8),规格 C(40),付款 L,日期时间 T)
 FOR i=1 To 200001
     INSERT INTO 测试表(入库单号,入库日期,物料名称,数量,单价,单位,规格,付款,日期时间) VALUES ('C'+PADL(i,6,'0'),{^2018-03-01}+INT(RAND()*10),'物料'+PADL(i,3,'0'),INT(RAND()*1000),INT(RAND()*100)*1.00,'个','',IIF(i%2=0,.t.,.f.),DATETIME())
 ENDFOR
 GO RECCOUNT() - 1
 REPLACE 入库日期 WITH {},单价 WITH 9.01 && 修改倒数2记录的日期为空,单价为小数

s1=SECONDS()
 SELECT 测试表
GO 1

 ** 下面4个参数,可以作为函数参数,在VFP9.0测试通过,10W调记录大概20秒
lnReccRows = RECCOUNT()  && 总记录数
lnPageSize = 20000      && 每页记录  
lnPageRows = 2           && 行标题行位置
lnPageCols = 2           && 第1列的位置
lnFormat = 1             && 是否根据字段设置格式

SET MARK TO "-"

PRIVATE oExcel,lnPageCount,lnWorkCount,lnPage,lnSheet,lnRows,lnFieldCount,lnStartRows,lnEndRows,lnStartCols,lnEndCols
 PRIVATE lnCols,lcSelect,lcRange,lcFormat,lcFormatNumber &&设置格式变量

lnFieldCount = AFIELDS(AryField)             && 字段数量和字段内容
lnPageCount = CEILING(lnReccRows/lnPageSize) && 计算需要总页数
lnStartRows = lnPageRows                     && 初始化单元格"开始行数"
lnStartCols = lnPageCols                     && 初始化单元格"开始列数"
lnEndRows = lnPageSize + lnPageRows          && 初始化单元格"结束行数"
lnEndCols = lnFieldCount + lnPageCols        && 初始化单元格"结束列数"

oExcel=Createobject('excel.application') && 创建电子表格
oExcel.DisplayAlerts = .F.               && 关闭 Excle 提示对话框
oExcel.Visible=.f.                       && 使电子表格可见 .t.
 oExcel.WorkBooks.Add                     && 创建工作簿
oExcel.ActiveWindow.WindowState = 2      && 最大化工作部
oExcel.Caption='数据导出'                && Excel标题


** -----------------------------------------------------------------------------------------------------------
** 工作表不够,增加工作表
lnWorkCount = oExcel.Worksheets.Count
 IF lnPageCount > lnWorkCount
    FOR lnPage = lnWorkCount + 1 To lnPageCount Step 1
        oExcel.Sheets.Add
    ENDFOR
 ENDIF

 ** -----------------------------------------------------------------------------------------------------------
 ** 设置工作表名称
For lnPage = 1 To lnPageCount STEP 1
     oExcel.sheets(lnPage).Name = '第' + ALLTRIM(STR(lnPage)) + '页'
Endfor

 ** -----------------------------------------------------------------------------------------------------------
 ** 利用剪贴板把DBF内容复制到EXCEL表
FOR lnSheet = 1 TO lnPageCount STEP 1 && 分别打开各个工作表
    oExcel.sheets(lnSheet).Activate
     lnRows = (lnSheet-1) * lnPageSize + 1 && 当前页数的第1个记录号
    lnPageMaxSize = IIF(lnPageSize * lnSheet > lnReccRows ,lnReccRows + lnPageSize - lnPageSize * lnSheet,lnPageSize) && 计算最后不满1页的记录数
    lnEndRows = lnPageMaxSize + lnPageRows

 ** -----------------------------------------------------------------------------------------------------------
     ** 设置格式
    IF lnFormat>0 && 等于0时,不进行格式设置
       FOR i=1 TO lnFieldCount
            lnCols = lnPageCols + i - 1
            ** 设置格式,选择区域
            oExcel.Range(oExcel.Cells( lnPageRows + 1 ,lnCols ),oExcel.Cells( lnEndRows ,lnCols )).Select

            DO CASE
               CASE INLIST(AryField(i,2),"C","V")     && 文本格式
                   lcFormat = "@"
               CASE AryField(i,2)="I"                 && 整数格式
                   lcFormat = "0_ "
               CASE INLIST(AryField(i,2),"B","N","F") && 小数格式
                   lcFormat = IIF(AryField(i,4) = 0,"0_ ","0."+REPLICATE("0",AryField(i,4))+"_ ")
               CASE AryField(i,2)="D"                 && 日期格式
                   lcFormat = "yyyy-m-d"
               CASE AryField(i,2)="T"                 && 日期时间格式
                   lcFormat = "yyyy-m-d hh:mm:ss"
               OTHERWISE                              && 其他通用格式
                   lcFormat = "G/通用格式"
            ENDCASE
            
            oExcel.Selection.NumberFormatLocal = lcFormat
     ENDFOR
     ENDIF

 ** -----------------------------------------------------------------------------------------------------------   
     ** 从当前位置开始,复制一页的记录作为文本复制到剪贴板上,3使用制表符分隔字段
    GO lnRows
     _vfp.DataToClip(ALIAS(),lnPageMaxSize,3)
     ** 选择区域,粘贴数据
     oExcel.Range(oExcel.Cells(lnStartRows , lnStartCols) ,oExcel.Cells(lnEndRows , lnEndCols)).Select
     oExcel.ActiveSheet.Paste && 粘贴数据
     oExcel.Columns.AutoFit   && 单元格宽度自动调整
     
 ENDFOR

 MESSAGEBOX(TRANSFORM(SECONDS()-S1))
 oExcel.Visible=.T.

 *!* oExcelApp.ActiveWorkbook.SaveAs(cExcelFile)       && 另存为
*!* oExcel.ActiveWorkbook.Save                        && 自动列宽
*!* oExcel.Workbooks.Close                            && 关闭表
*!* oExcel.Quit                                       && 退出Excel
 *!* Release oExcel  &&关闭进程
2018-03-23 13:52
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:191
帖 子:3147
专家分:8408
注 册:2015-3-25
收藏
得分:0 
好,刚测试一下,10W记录, I5 3470,8G,WIN7 64,
在有备注字段时,每页1W记录,花45秒
在没备注字段时,每页1W记录,花15秒
能否在有备注字段的时候,优化。。。
2018-03-24 10:50
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:191
帖 子:3147
专家分:8408
注 册:2015-3-25
收藏
得分:0 
以下是引用吹水佬在2018-3-24 23:24:38的发言:

发现了一个问题:
字符型字段的字符串第一个字符是双引号("),用_VFP.DataToClip()复制,粘贴结果可能会出现异常。
暂替换为全角双引号(")处理:
_VFP.DataToClip(cAlias, nPageRows, 3)    && 复制DBF记录
_CLIPTEXT = STRTRAN(_CLIPTEXT, '"', '"')
真好,我测试了,2W记录,每页2000,每改善M字段时,要15秒,改善后5秒,速度快了很多。

[此贴子已经被作者于2018-3-25 00:27编辑过]

2018-03-25 00:19
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:191
帖 子:3147
专家分:8408
注 册:2015-3-25
收藏
得分:0 
吹版,真棒。
经过你这样处理后,原来的数据不变,如 物料名称= "名称
导出到EXCEL后,还是 物料名称= "名称
比你27楼更加好,你27楼是用 全角的“代替 半角 "
不过,还没看明白,粘贴板上的内容是 """测试双引号AB""CD"" ,怎么到EXECL后是 "测试双引号AB"CD"

[此贴子已经被作者于2018-3-25 15:05编辑过]

2018-03-25 14:07
快速回复:发现1次EVALUATE()无法代替宏的,DBF转EXCEL
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.019188 second(s), 11 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved