教你用几行脚本轻松搞定文本导出

TXT 文本文件是我们常用的在应用之间传递数据的途径之一,因为它具有通用、灵活、易维护等诸多优点。不过并不是所有应用都提供了生成 txt 文件的功能,往往需要额外的程序设计和开发工作才能获得。这时如果能够有一个通用的工具软件,灵活地根据需要生成目标格式的文本,将能够极大地助力我们的业务工作。本文介绍的集算器就正是这样一款高效、灵活的通用工具软件,能够从不同数据源读取、计算并导出 txt 文件。

本文将着重介绍集算器的数据导出能力,而集算器本身强大的计算能力不是本文重点,因此文中没有刻意介绍数据源访问和计算过程。文中用到的函数请参看集算器文档《函数参考》。

简单导出数据

导出新文件

下面这个例子中,通过两行简单读入和输出,完成了从数据源到TXT 文件的导出。


A

1

=file("51.xlsx").xlsimport@t()

2

=file("学生成绩表.txt").export@t(A1)

 

A1读入excel 文件中的 5 年 1 班学生成绩,用来模拟可能通过计算得到的数据。

A2A1 的数据导出到一个新的 “学生成绩表.txt”文件中。

例子中使用了导出函数export。不过在这个最简单的例子中,我们没有指定额外的参数。由于没有指定 x 和 F,因此将导出 A1 中的所有字段,同时保持字段名不变。由于没有指定列分隔符参数 s,所以会用默认的 tab 分隔。不过函数使用了选项 @t,因此会将字段名(excel 文件的标题行)导出到第一行。

 

下图为导出的txt 文件:

undefined 

追加数据

假如“学生成绩表.txt”文件已经存在,此时我们需要在文件中再增加另一个班的成绩


A

1

=file("52.xlsx").xlsimport@t()

2

=file("学生成绩表.txt").export@a(A1)

 

A1读入要追加的5 年 2 班的学生成绩,数据结构保持相同 

A2把数据导出到已有的“学生成绩表.txt”文件中,因为文件中已有标题,只需导出数据,因此不要加函数选项 @t同时,通过选项@a 指明追加数据。

 

导出csv

csv 文件也是常见的纯文本文件,其中存储的表格数据以逗号分隔。如果要导出 csv 文件,有两种方式:在导出时象下图那样加选项 @c,或者增加分隔参数,写成 export@t(A1;",")两种方式结果都是一样的。


A

1

=file("51.xlsx").xlsimport@t()

2

=file("学生成绩表.txt").export@tc(A1)

导出结果如下:

学号, 姓名, 班级, 性别, 语文, 数学, 英语

110210, 徐赵亚,5(1), 男,80,60,86

110211, 王莼礼,5(1), 男,81,72,67

110212, 沈花容,5(1), 女,97,91,87

110213, 李晓梅,5(1), 女,86,69,73

复杂导出数据

在上面的例子中我们引入一些新的需求:

1、在结果文件中增加一个序号列

2、在最后增加一个平均成绩列,并对平均成绩进行格式化保留一位小数

3、不导出学号

4、列间分隔符采用“\t| ”。

undefined 

A1:读入数据。

A2#号在序表中表示记录编号,将它导出为结果中的序号列;指明导出姓名、班级、性别、语文、数学、英语列;表达式“string((语文 + 数学 + 英语 )/3,"#.0"): 平均”中,求出语文、数学、英语的平均数并格式化成只保留一位小数,命名导出的新列名为“平均”;最后一个参数指定列间分隔符为“\t| ”。

导出结果如下图所示:

undefined 

 

导出大量数据

我们还可以利用集算器提供的游标功能来处理大数据量的情况,游标在读取数据时从前向后遍历一次,逐条从数据源读取数据,而不是一次将所有数据读入内存,因此不会受到内存不足的限制。而且,集算器游标不仅可以应用于数据库,还可以应用于数据文件或者内存排列。

脚本如下图所示:

undefined 

导出结果如下:

undefined 

A1连接demo 数据库

A2打开订单表作为游标 

A3定义序号变量n,赋初值为 0

A4具体的导出过程,将游标所指的大数据导出到big.txt 文件中。

对于大数据量的情况我们把游标作为导出数据源,而在前面的普通导出情况下则是把序表作为导出数据源。除了游标中不能以#代表记录号自动产生序号以外,两者用法完全相同。

为了产生序号,导出时利用A3 中定义的变量 n,在每导出一条数据时加 1 后导出为序号列即可。

批量导出数据

我们还可以根据一个字段的不同值,批量导出数据。看下面这样一个实例。

原表结构如下

月份       编号       属性      单位      部门      加入时间    所属室

201305   1009       1          A          A1          201108      研发室

201305   1009       1          B         B1          201207      推广室

201305   1009       1          C         C1          201301     支撑室

201305   1009       1          D          D1         201109     服务室

201305   1013       2          C          C2         201302     支撑室

201305   1027       2          A          A3          201007     研发室

...       ...      ...      ...      ...      ...        ...

原表比较大,有400万条记录

 

期待结果

所属室的不同值批量导出TXT文件,呈现如下:

研发室.txt,内容如下:

月份      编号       属性      单位      部门      加入时间    所属室

201305   1009       1          A        A1             201108    研发室

201305   1027       2          A        A3             201007    研发室

推广室.txt,内容如下:

月份      编号       属性      单位      部门      加入时间    所属室

201305   1009       1        B          B1            201207    推广室

支撑室.txt,内容如下:

月份      编号       属性      单位      部门      加入时间    所属室

201305   1009       1         C        C1             201301    支撑室

201305   1013       2         C        C2             201302    支撑室

服务室.txt,内容如下:

月份      编号       属性      单位      部门      加入时间    所属室

201305   1009       1         D        D1             201109    服务室

 

正常的思路是按照“所属室”分组,将每个分组明细导出到以所属室命名的 TXT 文件中,但由于 SQL 无法保存分组内容(分组后必须聚合),实现起来很麻烦,而且由于数据量大,需要使用游标分批向 TXT 追加写,非常麻烦。

采用SPL 循环游标的方式能很好地处理这个问题,脚本如下:


A

B

1

=db.cursor(“select * from tb1”)

2

for A1,10000


3


= A2.group(所属室)

4


>B3.(file("D:\\"+~. 地区 +".txt").export@at(~))

A1:根据 sql 创建数据库游标

A2-B4:对游标 A1 循环,每次取 10000 条记录,并按照“所属室”分组,并以追加方式分别导出到以“所属室”命名的 txt 文件中

 

 

示例

示例1

企业给员工发工资一般都通过银行代发的方式。银行都提供了网上服务,企业可以通过这个途径来完成自助工资发放,具体的做法是:

银行提供了一个代发工资的文本文件格式,企业用户只要按格式编写此文件,再通过网上银行上载此文件,就可以完成工资发放。

下面我们就来看看如何利用集算器方便地完成代发工资文本文件的生成。

我们以民生银行为例,其文件格式如下:

ATNU:0019999

MICN:

CUNM: 北京 XXXX 技术有限公司

MIAC:0110014180030254

EYMD:1

TOAM:80576.39

COUT:5

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

6226220101871111|19944.65| 赵爱润 ||

6226220101872222|18349.08| 孙学乾 ||

6226220101873333|15955.72| 王老集 ||

6226220101874444|14360.15| 张小算 ||

6226220101875555|11966.79| 李大器 ||

 

此文件前 8 行是文件头,第 1、2、5、8 行内容固定不变,第 3 行是企业名称,第 4 行是企业在民生银行的账号,第 6 行是本次发工资的总金额,第 7 行是发工资的总笔数。从第 9 行开始是具体的工资信息,第一项是员工工资账号,第二项是工资金额,第三项是员工姓名,第四、五项空着不填就行。各项之间用竖线分隔。

此文本文件的格式要求非常严格,不能出错,因此不适合财务人员直接编辑,需要通过程序生成。

企业与工资相关的有两个 excel 表,一个是员工表,另一个是工资表,如下两图所示。

undefined 

undefined 

账务人员负责填好员工工资表后,就可以打开集算器 ide,运行预先编写好的 dfx 程序了:

undefined 

A1读入编写的员工表

B1读入编写的工资表

A2按姓名将两张表合并成一张表

A3打开要保存的代发工资文件 

A4 到 B7 中逐行写入文件头:其中 B6 是工资总额,从 A2 中算出银行实发总额填入;A7 是本次代发的总笔数。

A8导出生成代发工资文件,分别是工资卡号、工资金额、姓名、空列、空列 (最后两列是不需要填的,所以用备注列代表)。

脚本中除了 A4 格是用替换写入以外,其它格都用了 @a 选项,表示是追加写入。

 

示例 2(文末附示例文件)

当前存在一个格式不规则的Migration 表(如下图),我们需要将表中的信息整理成标准的表格形式。

undefined 


A

1

=file("Migration.xlsx").xlsimport@t()

2

=A1.to(6,)

3

=A2.new(_1:Country,"Men":Sex,"Native":Born,_2:Y1995,_3:Y2000,_4:Y2003,_5:Y2004)

4

=A2.new(_1:Country,"Men":Sex,"Foreign..born":Born,_6:Y1995,_7:Y2000,_8:Y2003,_9:Y2004)

5

=A2.new(_1:Country,"Women":Sex,"Native":Born,_10:Y1995,_11:Y2000,_12:Y2003,_13:Y2004)

6

=A2.new(_1:Country,"Women":Sex,"Foreign..born":Born,_14:Y1995,_15:Y2000,_16:Y2003,_17:Y2004)

7

=[A3,A4,A5,A6].conj().select(Country!=null)

8

=file("Migration.txt").export@t(A7)

A1:读取表格;

A2:从第六行开始取序列的部分成员组成新序列;

A3-A6:对表中的数据进行整理,根据不同的过滤内容,筛选生成新的序表;

A7:对A3A4A5A6进行和列,并且筛选出country不为空的数据;

A8:将A7的内容导出为Migration.txtexport后面加上@t,使列名作为第一条记录写在字符串开头。

导出的txt内容如下:

undefined 

总结

在数据导出过程中,集算器提供了 write()export() 两个函数,前者是逐行写入,后者是批量写入。函数提供了参数和函数选项两种控制方法,使用不同的参数或函数选项,我们可以指定是否导出字段名 / 标题、是否导出所有字段、是否使用新的字段名、追加还是替换文件、使用哪个字符做分隔参数等等选择。

集算器即装即用,易学易用,如果要分析的数据是一次性或临时性的,润乾集算器每个月都提供免费试用授权,可以循环免费使用,几行脚本就能帮你轻松解决很多问题,更多例子参见集算器技术文档和技术论坛乾学院

示例 2