資料檔案合併與拆分

bubblegum發表於2020-11-19

在資料處理業務中,經常要把檔案結構相同或近似相同的資料檔案合併成一個檔案,或者將一個比較大的資料檔案拆分成小的資料檔案。本文將介紹文字檔案和 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表示遞迴查詢所有子目錄下的檔案。

上面這段指令碼是假設記憶體能夠裝下合併以後的全部資料,如果裝不下,那麼應該用下面這段指令碼:


A B C
1 =directory@p("e:/orders/*.txt") =file("e:/orders.txt")
2 for A1 =file(A2).cursor@t()
3
if #A2==1 =B1.export@t(B2)
4
else =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檔案

同樣地,如果記憶體裝不下合併後的所有資料,則使用下面這段指令碼:


A B C
1 =directory@p("e:/orders/*.txt") =file("e:/orders.txt")
2 for A1 =file(A2).cursor@t(ID,Company,Area,OrderDate,Amount)
3
if #A2==1 =B1.export@t(B2)
4
else =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檔案

同樣地,如果記憶體裝不下合併後的所有資料,則使用下面這段指令碼:


A B C
1 =directory@p("e:/orders/*.xlsx") =file("e:/orders.xlsx")
2 for A1 =file(A2).xlsimport@tc().derive(filename@n(A2):PartName)
3
if #A2==1 =B1.xlsexport@ts(B2)
4
else =B1.xlsexport@as(B2)

合併後的orders.xlsx檔案部分資料如下圖所示:

..

 

二、  檔案拆分

1.  分組拆分

對檔案中資料進行分組,把每組資料單獨存為一個檔案,用組名為檔案命名。

示例:在訂單表Excel檔案中有各種零件的訂單,請把同種零件的訂單各存為一個Excel檔案,以便傳送給零件生產部門。

esProc SPL指令碼如下:


A B
1 =file(“e:/orders/orders.xlsx”).xlsimport@t()   =A1.group(partName)
2 for B1 =file("e:/parts/"+A2(1).partName+”.xlsx”).xlsexport@t(A2)  

A1   讀入所有原始資料

B1   按partName分組

A2   迴圈每個零件組的訂單資訊

B2   以零件名稱作為檔名,匯出零件資訊

 

如果原檔案很大,不能全部裝入記憶體,那麼應該使用遊標方式讀數,指令碼如下:


A B C D
1 =file(“e:/orders/orders.xlsx”).xlsimport@tc()  
2 for A1,50000 =A2.group(partName)

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

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

else =C3.xlsexport@t(B3)

A1   建立遊標讀取原始資料

A2   迴圈遊標讀數,每次讀50000行(讀多少行根據記憶體大小決定)

B2   對每次讀取的資料按partName分組

B3   迴圈每組零件

C3   以零件名稱作為檔名建立檔案物件

C4-D5   如果檔案已存在,則用@a追加寫入零件訂單資訊,不存在則用@t先寫入列名再匯入資料

 

2.  記錄佔據多行的拆分

在文字檔案中,一條資料記錄是由多行資料組成的,在拆分成小檔案時,要識別哪幾行是同一條資料記錄,保證同一條資料記錄不會被拆分到兩個檔案中。

示例1:有網站執行日誌檔案log.txt,每條日誌由5行組成,現在需要把這個日誌檔案拆分成一些小檔案,每個檔案由1000條日誌組成。

esProc SPL指令碼如下:


A B
1 =file(“e:/log.txt”:”UTF-8”).cursor@s()
2 for 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指令碼如下:


A B
1 =file(“e:/log.txt”:”UTF-8”).read@n()   =A1.select(~!="")
2 =B1.group@i(pos(~,"[")==1).cursor()
3 for 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個組,內層迴圈每組的成員(即資料行),將每行追加寫入檔案

 

《 》中有更多相關計算示例。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69957599/viewspace-2735044/,如需轉載,請註明出處,否則將追究法律責任。

相關文章