数据文件合并与拆分

在数据处理业务中,经常要把文件结构相同或近似相同的数据文件合并成一个文件,或者将一个比较大的数据文件拆分成小的数据文件。本文将介绍文本文件和 Excel 文件合并及拆分会遇到的几种情况,并提供用 esProc SPL 编写的代码示例。esProc 是专业的数据计算引擎,SPL 中有完善的文件导入、导出及目录操作函数,非常适合做数据文件的合并及拆分工作。


一、  文件合并

1.  同构文本文件合并

在某个文件目录下有多个文本文件,这些文件表头和列结构完全相同,只是数据行数和数据内容不同,需要将这些文件的数据全部合并到一个文本文件中,共用同一个表头。

示例:在e:/orders目录下有每日的订单文本文件,每个文件的结构相同,第一行是列名,第二行开始是数据,如下图所示,请将它们合并成一个订单表文件orders.txt。

esProc SPL脚本如下:

A注释

1=directory@p("e:/orders/*.txt")返回orders目录所有txt文件的完整路径名

2=A1.conj(file(~).import@t())合并所有文件的数据

3=file("e:/orders.txt").export@t(A2)将合并后的数据写入orders.txt文件

如果e:/orders还有子目录,子目录中的txt文件也需要一起合并,那么把A1格改成=directory@ps("e:/orders/*.txt"),选项@s表示递归查找所有子目录下的文件。

上面这段脚本是假设内存能够装下合并以后的全部数据,如果装不下,那么应该用下面这段脚本:

ABC

1=directory@p("e:/orders/*.txt")=file("e:/orders.txt")

2for A1=file(A2).cursor@t()

3if #A2==1 =B1.export@t(B2)

4else=B1.export@a(B2)

A1列出目录中的所有txt文件的完整路径名称,如果要查找子目录,则加上@s选项

A2对列出的文件进行循环

B2用游标读取每一个文件,@t表示第一行是列名

B3-C4将B2游标中数据导出,第一次要导出列名,其后用@a进行追加


2.  结构近似的文本文件合并

如果文件结构并不是完全相同,比如列的顺序不一样、列数不一样,但各文件都含有共同的几列,想要把这些共同列的数据都合并到一个文件中。合并这些文件时,需要按指定顺序读出每个文件中的这些共同列数据。

示例:还是上面这个例子,已知所有订单文件都有ID、Company、Area、OrderDate、Amount这5列,但各文件中列的顺序并不相同,有的文件还有其它一些列,请将各文件中的这5列数据合并到orders.txt文件中。

esProc SPL脚本如下:

A注释

1=directory@p("e:/orders/*.txt")返回orders目录所有txt文件的完整路径名

2=A1.conj(file(~).import@t(ID,Company,Area,OrderDate,Amount))按指定的5列顺序读出各文件数据,然后合并所有文件的数据

3=file("e:/orders.txt").export@t(A2)将合并后的数据写入orders.txt文件

同样地,如果内存装不下合并后的所有数据,则使用下面这段脚本:

ABC

1=directory@p("e:/orders/*.txt")=file("e:/orders.txt")

2for A1=file(A2).cursor@t(ID,Company,Area,OrderDate,Amount)

3if #A2==1 =B1.export@t(B2)

4else=B1.export@a(B2)


3.  文件名转成列数据

在合并数据的同时,需要为合并后的数据增加一列,并用合并前的文件名给此列赋值,以便标记数据类别或来源。

示例:在e:/orders目录下有各种零件的订单Excel文件,文件名就是零件的名字,比如tyre.xlsx、engine.xlsx……等,每个文件的结构相同,第一行是列名,第二行开始是数据,如下图所示,请将它们合并成一个订单表文件orders.xlsx,并增加一列PartName用来记录零件的名字。

esProc SPL脚本如下:

A注释

1=directory@p("e:/orders/*.xlsx")返回orders目录所有Excel文件的完整路径名

2=A1.conj((fn=filename@n(~),file(~).xlsimport@t().derive(fn:PartName)))先将文件名定义为临时变量fn,读入文件后,增加一列PartName,并用fn赋值。最后将各文件数据合并

3=file("e:/orders.xlsx").xlsexport@t(A2)将合并后的数据写入orders.xlsx文件

同样地,如果内存装不下合并后的所有数据,则使用下面这段脚本:

ABC

1=directory@p("e:/orders/*.xlsx")=file("e:/orders.xlsx")

2for A1=file(A2).xlsimport@tc().derive(filename@n(A2):PartName)

3if #A2==1=B1.xlsexport@ts(B2)

4else=B1.xlsexport@as(B2)

合并后的orders.xlsx文件部分数据如下图所示:


二、  文件拆分

1.  分组拆分

对文件中数据进行分组,把每组数据单独存为一个文件,用组名为文件命名。

示例:在订单表Excel文件中有各种零件的订单,请把同种零件的订单各存为一个Excel文件,以便发送给零件生产部门。

esProc SPL脚本如下:

AB

1=file(“e:/orders/orders.xlsx”).xlsimport@t()   =A1.group(partName)

2for B1=file("e:/parts/"+A2(1).partName+”.xlsx”).xlsexport@t(A2)  

A1读入所有原始数据

B1按partName分组

A2循环每个零件组的订单信息

B2以零件名称作为文件名,导出零件信息


如果原文件很大,不能全部装入内存,那么应该使用游标方式读数,脚本如下:

ABCD

1=file(“e:/orders/orders.xlsx”).xlsimport@tc()  

2for A1,50000=A2.group(partName)

3for B2=file("e:/parts/"+B3(1).partName+”.xlsx”)

4if C3.exists()=C3.xlsexport@a(B3)

5else=C3.xlsexport@t(B3)

A1创建游标读取原始数据

A2循环游标读数,每次读50000行(读多少行根据内存大小决定)

B2对每次读取的数据按partName分组

B3循环每组零件

C3以零件名称作为文件名创建文件对象

C4-D5如果文件已存在,则用@a追加写入零件订单信息,不存在则用@t先写入列名再导入数据


2.  记录占据多行的拆分

在文本文件中,一条数据记录是由多行数据组成的,在拆分成小文件时,要识别哪几行是同一条数据记录,保证同一条数据记录不会被拆分到两个文件中。

示例1:有网站运行日志文件log.txt,每条日志由5行组成,现在需要把这个日志文件拆分成一些小文件,每个文件由1000条日志组成。

esProc SPL脚本如下:

AB

1=file(“e:/log.txt”:”UTF-8”).cursor@s()

2for A1,5000=file(“e:/log/log_”/#A2/”.txt”).export(A2)

A1用游标读取日志文件数据,@s表示将整行读成一个字符串

A2循环游标,每次取5000行,刚好是1000条日志

B2按循环序号生成日志文件名,如log_1.txt、log_2.txt……,然后将当前取出的所有行写入


示例2:有程序运行日志文件log.txt如下图所示,每条日志由不确定的几行组成,每条日志由中括号开头,其后只要不是中括号开头的行,都与它属于同一条日志。现在需要把这个日志文件拆分成一些小文件,每个文件由1000条日志组成。

esProc SPL脚本如下:

AB

1=file(“e:/log.txt”:”UTF-8”).read@n()   =A1.select(~!="")

2=B1.group@i(pos(~,"[")==1).cursor()

3for A2,1000=file(“e:/log/log_”/#A3/”.txt”)

4=A3.(~.(B3.write@a(~)))

A1打开日志文件读取数据,@n表示将每一行读成一个字符串,所有串组成一个序列返回

B1筛选出非空的行

A2按行是否用中括号开头作为分组条件,中括号开头的作为一个新组,不是则并到当前组。最后把所有组序列转换成游标

A3循环游标,每次取1000个组,即1000条日志

B3按循环序号生成日志文件名,如log_1.txt、log_2.txt……

B4两层循环,外层是循环1000个组,内层循环每组的成员(即数据行),将每行追加写入文件


SPL CookBook》中有更多相关计算示例。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 本文总结使用Python对常见的数据文件进行读写操作。 注:我这有个学习基地,里面有很多学习资料,感兴趣的+Q群:...
    PathonDiss阅读 525评论 0 0
  • 大多数JAVA程序猿都选择使用POI或者HSSFWorkbook等第三方类库来实现Excel自动化合并,这样一来不...
    小黄鸭呀阅读 970评论 0 0
  • 不得不说 使用shell 操作文件 还是很快 很锋利,几个命令就搞定的事情就不要 在使用 什么 stream i...
    Helen_Cat阅读 3,237评论 0 3
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,474评论 16 22
  • 创业是很多人的梦想,多少人为了理想和不甘选择了创业来实现自我价值,我就是其中一个。 创业后,我由女人变成了超人,什...
    亦宝宝阅读 1,801评论 4 1