VFP数据导出全攻略:Excel、PDF、CSV、HTML、JSON,一行代码搞定
数据导出是所有业务系统的标配功能。客户要报表、财务要对账、领导要看图——你总不能让人家直接打开你的DBF文件吧。VFP支持多种导出格式,今天全部讲透,总有一种适合你的场景。
一、导出到CSV:最通用的交换格式
CSV是万能格式,任何系统都能打开,VFP原生支持。
1.1 COPY TO命令(最简单)
USEcustomersCOPY TOcustomers.csv TYPE CSV一行命令,自动生成CSV文件。TYPE CSV会把每个字段用逗号分隔,第一行自动加字段名。
1.2 自定义分隔符
*-- 用分号分隔(欧洲常用)COPY TOcustomers.csv TYPE DELIMITED WITH ; WITH BLANK*-- 用TAB分隔(便于粘贴到Excel)COPY TOcustomers.tsv TYPE DELIMITED WITH TAB*-- 用双引号包裹字符串COPY TOcustomers.csv TYPE DELIMITED WITH "1.3 导出前筛选数据
*-- 只导出活跃客户SELECT * FROM customers WHERE status = "active" ;AND registration_date >= {^2026-01-01} ;INTOCURSOR cur_activeCOPY TO active_customers_2026.csv TYPE CSV二、导出到Excel:COM自动化
需要格式化的Excel报表(合并单元格、公式、颜色),用COM自动化最灵活。
2.1 最简单的两行代码
*-- VFP数据直接写入ExcelLOCAL oExcel, oWorkbook, oSheetoExcel = CREATEOBJECT("Excel.Application")oExcel.Visible = .F.&& 后台运行,不显示窗口oWorkbook = oExcel.Workbooks.Add()oSheet = oWorkbook.Sheets(1)oSheet.Name = "客户清单"*-- 写入表头USEcustomers SHARED=AFIELDS(aFields)FOR i = 1 TO ALEN(aFields, 1)oSheet.Cells(1, i).Value = aFields[i, 1]ENDFOR*-- 写入数据SELECT * FROM customers INTO CURSOR cur_custnRow = 2SCANFOR i = 1 TO FCOUNT()oSheet.Cells(nRow, i).Value = EVALUATE(FIELD(i))ENDFORnRow = nRow + 1ENDSCAN*-- 保存并关闭*-- 51 = xlOpenXMLWorkbook (.xlsx)oWorkbook.SaveAs("customers.xlsx", 51)oWorkbook.Close(.F.)oExcel.Quit()RELEASE oExcel? "导出完成:customers.xlsx"2.2 格式化Excel(加粗、颜色、列宽自适应)
LOCAL nLastRownLastRow = RECCOUNT() + 1*-- 表头加粗 + 蓝色背景oSheet.Range("A1").Resize(1, FCOUNT()).Font.Bold = .T.oSheet.Range("A1").Resize(1, FCOUNT()).Interior.Color = RGB(0, 112, 192)oSheet.Range("A1").Resize(1, FCOUNT()).Font.Color = RGB(255, 255, 255)*-- 列宽自适应oSheet.UsedRange.Columns.AutoFit()*-- 金额列格式化为货币(根据实际列号调整)oSheet.Range("D2").Resize(nLastRow - 1, 1).NumberFormat = Chr(165) + "#,##0.00"*-- 设置打印区域oSheet.PageSetup.PrintArea = oSheet.UsedRange.AddressoSheet.PageSetup.Orientation = 2 && 2 = xlLandscape 横向2.3 导出多张Sheet
*-- 同一工作簿导出多个SheetoWorkbook = oExcel.Workbooks.Add()*-- Sheet1:客户清单oSheet1 = oWorkbook.Sheets(1)oSheet1.Name = "客户"EXPORT_TO_SHEET(oSheet1, "customers", "客户清单")*-- Sheet2:订单汇总oSheet2 = oWorkbook.Sheets(2)oSheet2.Name = "订单"oSheet2.Range("A1").Value = "customer_id"oSheet2.Range("B1").Value = "order_cnt"oSheet2.Range("C1").Value = "total"SELECTcustomer_id, COUNT(*) AS order_cnt, SUM(amount) AS total ;FROM orders GROUP BY customer_id INTO CURSOR cur_orders*... 写入数据...*-- Sheet3:月度统计(同上结构)*...oWorkbook.SaveAs("business_report.xlsx", 51)oWorkbook.Close(.F.)oExcel.Quit()*-- 通用导出函数FUNCTION EXPORT_TO_SHEET(oSheet, cCursor, cSheetName)oSheet.Name = cSheetNameSELECT (cCursor)=AFIELDS(aFields)* 写表头FOR i = 1 TO ALEN(aFields, 1)oSheet.Cells(1, i).Value = aFields[i, 1]ENDFOR* 写数据nRow = 2SCANFOR i = 1 TO FCOUNT()oSheet.Cells(nRow, i).Value = EVALUATE(FIELD(i))ENDFORnRow = nRow + 1ENDSCANENDFUNC⚠️ 注意:宏代换
&无法正确处理含分号的多行 SQL 语句。如需动态执行 SQL,建议改用ndX或直接传 Cursor 名而不是 SQL 文本。
三、导出到HTML:网页展示最方便
HTML文件用浏览器直接打开,无需任何软件,最适合分享。
3.1 一行命令导出HTML表格
USEcustomersCOPY TOcustomers.html TYPE HTML生成的HTML是一个标准的<table>表格,可以直接在浏览器打开,也可以内嵌到网页。
3.2 美化HTML表格
VFP TEXTMERGE 是生成动态 HTML 的利器。关键是理解两个转义规则的组合拳:
\<<→ 输出字面字符 <<<expr>>→ 计算表达式并输出结果
这样 HTML 标签用 \<< 转义,变量用 <<>> 计算,两不耽误。
*-- 生成带样式的HTML报表FUNCTION ExportToHTML(cCursor, cTitle, cOutFile)SELECT (cCursor)* 初始化HTML头尾片段TEXT TO cHead TEXTMERGE NOSHOW PRETEXT 7\SLIDERPLACEHOLDER0ENDPLACEHOLDER\<html>\<head>\<meta charset="utf-8">\<title><<cTitle>>\</title>\<style>body { font-family: Arial, sans-serif; margin: 20px; }h1 { color: #1a73e8; border-bottom: 2px solid #1a73e8; padding-bottom: 8px; }table { border-collapse: collapse; width: 100%; }th { background: #1a73e8; color: white; padding: 10px; text-align: left; }td { padding: 8px; border-bottom: 1px solid #ddd; }tr:hover { background: #f5f5f5; }tr:nth-child(even) { background: #fafafa; } .amount { text-align: right; } .date { color: #666; }\</style>\</head>\<body>\<h1><<cTitle>>\</h1>\<p>导出时间:<<TTOC(DATETIME())>></p>\<table>\<tr>ENDTEXTTEXT TO cTail TEXTMERGE NOSHOW PRETEXT 7\</table>\<p style="color:#888;font-size:12px;">共 <<RECCOUNT()>> 条记录</p>\</body>\</html>ENDTEXT* 写入表头LOCAL cHtml, i, cFieldName, cValcHtml = cHeadFOR i = 1 TO FCOUNT()cFieldName = FIELD(i)cHtml = cHtml + \<th> + cFieldName + \</th> + CHR(13)+CHR(10)ENDFORcHtml = cHtml + \</tr> + CHR(13)+CHR(10)* 写入数据行SCANcHtml = cHtml + \<tr>FOR i = 1 TO FCOUNT()cVal = TRANSFORM(EVALUATE(FIELD(i)))IF"金额"<code style="background: #f5f5f5; padding: 2px 4px; border-radius: 2px;">FIELD(i) OR"价格"</code>FIELD(i) OR"总额"$FIELD(i)cHtml = cHtml + \<td class="amount"> + cVal + \</td>ELSEcHtml = cHtml + \<td> + cVal + \</td>ENDIFENDFORcHtml = cHtml + \</tr> + CHR(13)+CHR(10)ENDSCANcHtml = cHtml + cTailSTRTOFILE(cHtml, cOutFile)ENDFUNC*-- 使用USEcustomersExportToHTML("customers", "客户清单", "customers.html")TEXTMERGE 转义规则对照表:
\<< | < | |
<<expr>> | ||
\\ | \ |
四、导出到PDF:打印存档必备
4.1 Excel转PDF(通过COM)
*-- 先导出Excel,再另存为PDF*--(需要系统已安装虚拟PDF打印机,如 Microsoft Print to PDF)oExcel = CREATEOBJECT("Excel.Application")oWorkbook = oExcel.Workbooks.Add()*... 写入数据(同2.1节)...oWorkbook.SaveAs("report_temp.xlsx", 51)* ExportAsFixedFormat 参数:0=PDF,1=XPSoWorkbook.ExportAsFixedFormat(0, "report.pdf")oWorkbook.Close(.F.)oExcel.Quit()⚠️
ExportAsFixedFormat需要系统安装了虚拟 PDF 打印机(Windows 10+ 自带 Microsoft Print to PDF,Windows 11 带 Microsoft Print to PDF 或 HP Smart)。无打印机时会报错。
4.2 VFP报表直接输出PDF
VFP 标准 ReportListener 没有直接指定输出文件名的内置方法。要输出 PDF,标准做法是通过 Windows 虚拟打印机:
*-- 方式一:静默打印到默认打印机(最通用)LOCAL oListeneroListener = CREATEOBJECT("ReportListener")oListener.ListenerType = 0 && 0=输出到打印机oListener.QuietMode = .T.&& 禁止打印对话框* 如需指定打印机名,用 CommandClausesoListener.CommandClauses = ""REPORTFORM myreport OBJECT oListener TO PRINTER NOCONSOLE*-- 方式二:Print to PDF(Windows 10+)* 将 "Microsoft Print to PDF" 设为默认打印机后,* 用方式一即可得到 PDF 文件原理说明: VFP ReportListener 的 ListenerType = 0 将报表交给 Windows 打印机处理。只要系统有一个虚拟 PDF 打印机(如 Microsoft Print to PDF、Foxit PDF Printer 等),打印输出即为 PDF 文件。通过 QuietMode = .T. 可以静默完成,不弹打印对话框。
如果需要指定输出路径,有两个思路:
临时修改默认打印机(适合一次性导出):
*-- 保存原默认打印机cOldPrinter = SET("PRINTER", 3) && 获取当前默认打印机*-- 临时切换到 PDF 打印机DO WHILE SET("PRINTER", 3) # "Microsoft Print to PDF"SET PRINTER TO NAME "Microsoft Print to PDF"ENDDO*-- 执行报表LOCAL oListeneroListener = CREATEOBJECT("ReportListener")oListener.ListenerType = 0oListener.QuietMode = .T.REPORTFORM myreport OBJECT oListener TO PRINTER NOCONSOLE*-- 恢复原打印机IF !EMPTY(cOldPrinter)SET PRINTER TO NAME (cOldPrinter)ENDIF用 GDI+ 将报表页面截图存为 PDF(适合无打印机的服务端场景,需要配合 ReportListener.Render)。
⚠️ 不要用
AddReportObjectProperty("PDF_DEVICE", ...)——这不是 VFP ReportListener 基类的标准方法,标准 VFP 里这个方法不存在,调用会报错"找不到属性或方法"。
五、导出到JSON
JSON在API时代是必备格式:
*-- Cursor转JSONFUNCTIONCursorToJSON(cCursor, cOutFile)SELECT (cCursor)LOCAL cJson, i, cFname, cValcJson = "[" + CHR(13)+CHR(10)SCANcJson = cJson + " {" + CHR(13)+CHR(10)FOR i = 1 TO FCOUNT()cFname = FIELD(i)cVal = TRANSFORM(EVALUATE(cFname))* 处理字符串中的引号IFVARTYPE(EVALUATE(cFname)) = "C"cVal = ['"] + STRTRAN(cVal, ['"], ['"]) + ['"]cJson = cJson + ' "' + cFname + '": "' + cVal + '"'ELSEcJson = cJson + ' "' + cFname + '": ' + cValENDIFIF i < FCOUNT()cJson = cJson + ","ENDIFcJson = cJson + CHR(13)+CHR(10)ENDFORcJson = cJson + " }"IF !EOF()cJson = cJson + ","ENDIFcJson = cJson + CHR(13)+CHR(10)ENDSCANcJson = cJson + "]" + CHR(13)+CHR(10)STRTOFILE(cJson, cOutFile)ENDFUNC*-- 使用SELECTcustomer_id, customer_name, registration_date, amount ;FROMcustomers ORDER BY amount DESC ;INTOCURSOR cur_topCursorToJSON("cur_top", "top_customers.json")六、一键导出工具函数
写一个通用导出函数,支持任意格式:
DEFINE CLASS DataExporter AS CustomFUNCTION Export(cSQL, cOutFile, cFormat) &cSQL INTO CURSOR cur_expDO CASECASE cFormat = "CSV"COPY TO (cOutFile) TYPE CSVCASE cFormat = "HTML"THIS.ExportHTML("cur_exp", "数据报表", cOutFile)CASE cFormat = "JSON"THIS.ExportJSON("cur_exp", cOutFile)CASE cFormat = "XLSX"THIS.ExportExcel("cur_exp", cOutFile)CASE cFormat = "TXT"COPY TO (cOutFile) TYPE DELIMITED WITH BLANKOTHERWISE ? "不支持的格式:" + cFormatRETURN.F.ENDCASE ? "导出完成:" + cOutFileRETURN.T.ENDFUNCFUNCTION ExportHTML(cCursor, cTitle, cOutFile)* 见3.2节实现ENDFUNCFUNCTION ExportJSON(cCursor, cOutFile)* 见第5节实现ENDFUNCFUNCTION ExportExcel(cCursor, cOutFile)* 见2.1节实现ENDFUNCENDDEFINE*-- 使用示例oExp = CREATEOBJECT("DataExporter")oExp.Export("SELECT * FROM customers", "customers.csv", "CSV")oExp.Export("SELECT * FROM customers", "customers.html", "HTML")oExp.Export("SELECT * FROM customers", "customers.json", "JSON")oExp.Export("SELECT * FROM customers", "customers.xlsx", "XLSX")总结
记住一个原则:能用CSV解决的不用Excel,能用HTML的不用PDF。除非对方有明确的格式要求,否则越简单的格式越通用、越省事。
夜雨聆风