匯入 EDI 檔案到 DataStore
在台灣寫程式常常會需要使用到其他公司的資料交換,而大部份的合作夥伴都很多都會使用EDI檔案傳遞,因此處理EDI檔案就成了家常便飯,但有時候又不想要遇到一個專案就要再寫一次,所以幾乎都將它轉成PFC來使用。
上一次提到了 EDI 轉出 Function,所以這次來看看轉入EDI檔案的 Function怎麼做吧。
Function 名稱:f_edi2ds
回傳值:Long
傳遞參數:ads_dest[datastore][refrence]、as_file[string][readonly]、as_error[string][refrence]
與之前轉出EDI作法有點不一樣的地方,是在於取得 DataObject 的 DataWindow 欄位屬性時,我直接使用了幾個陣列(ll_collimit[]、ls_colname[]、ls_coltype[])來儲存,上次是使用一個structure來儲存,結果是相同,寫法不同,可以提供一個比較參考。
其次,這次轉入EDI檔案時欄位長度的參考,我是設計在每個欄位的 Edit.Limit 上,所以這個Function 使用時只要設計好 DataWindow 的模型就很好用了。
其次,使用上需要特別注意的地方是[日期時間]、[日期]、[時間]的轉換方式,我的設計上是假設EDI上的欄位日期是西元年的 YYYYMMDDHHMMSS 的格式的,所以 Datetime
欄位的 Limit 可以設定 8、10、14、16碼的,怎麼說呢?
假設日期欄來源資料為 YYMMDDHHMM的話,後面SS會自動補上00
例如:201208091325 -> 20120809132500 -> 2012/8/9 13:25:00
例如:2012080913 -> 20120809130000 -> 2012/8/9 13:00:00
如此可以簡化不少操作
倘偌需要更多格式的日期轉換就需要改寫轉換規則就可以了。
上一次提到了 EDI 轉出 Function,所以這次來看看轉入EDI檔案的 Function怎麼做吧。
Function 名稱:f_edi2ds
回傳值:Long
傳遞參數:ads_dest[datastore][refrence]、as_file[string][readonly]、as_error[string][refrence]
/*
將ED文字檔(as_file)I匯入到 DataStore(ads_dest)
EDI切割模式依照 dataObject 的 column.limit 訂定的長度
*/
Integer li_ColCount,li_Pos,li_Col,li_file
Long ll_collimit[],ll_rc,ll_totl,ll_cc,ll_new
String ls_colname[],ls_coltype[],ls_data,ls_val,ls_date,ls_time
Datetime ldt_1
boolean lb_fin
//檔案存在否?
IF not FileExists(as_file) THEN Return -1
//DataStore存在否?
IF isnull(ads_dest) OR not isValid(ads_dest) THEN
Return -1
END IF
//欄位存在否?
li_ColCount = integer(ads_dest.Describe("datawindow.column.count"))
IF li_ColCount <= 0 THEN Return -1
ll_totl = 0
//取得欄位屬性
FOR li_Col=1 TO li_ColCount
ls_colname[li_Col] = ads_dest.Describe("#" + string(li_Col) + ".Name")
ll_collimit[li_Col] = Integer(ads_dest.Describe("#" + string(li_Col) + ".Edit.Limit"))
//合計欄位總長度
ll_totl += ll_collimit[li_Col]
ls_coltype[li_Col] = lower(ads_dest.Describe("#" + string(li_Col) + ".ColType"))
//排除括弧字元
li_Pos = Pos(ls_coltype[li_Col] , "(")
IF li_Pos > 0 THEN
ls_coltype[li_Col] = Left(ls_coltype[li_Col] , li_Pos - 1)
END IF
NEXT
//開啟檔案(以LinMode讀取)
li_file = FileOpen(as_file , LineMode! , Read! ,LockReadWrite!)
IF li_file <= 0 THEN Return -2
ll_cc = 0
//逐行讀取
do while fileRead(li_file , ls_data) >= 0
//行數計數
ll_cc ++
//筆對長度
IF len(ls_data) < ll_totl THEN
as_error += "第" + String(ll_cc) + "行長度過少:" + String(len(ls_data)) +&
"<" + String(ll_totl) + "~r~n"
Continue
END IF
//新增一筆ROW到DataStore
ll_new = ads_dest.InsertRow(0)
li_pos = 1 //定位歸0
lb_fin = true //錯誤標記歸0
FOR li_col = 1 TO li_ColCount
//讀取指定位置範圍字串
ls_val = MidA(ls_data ,li_pos , ll_collimit[li_Col])
//依照欄位類型轉換
Choose Case ls_coltype[li_Col]
Case "char"
//文字
IF trim(ls_val) = "" THEN SetNull(ls_val)
ads_dest.SetItem(ll_new , li_col , ls_val)
Case "datetime"
//日期時間
IF trim(ls_val) <> "" THEN
ls_date = left(ls_val,4)+"/"+mid(ls_val,5,2)+"/"+mid(ls_val,7,2)
IF not isDate(ls_date) THEN
as_error += "第"+String(ll_cc)+"行,位置:"+String(li_pos)+",長度:"+&
String(ll_collimit[li_Col])+"無法轉換Datetime~r~n"
lb_fin = false
EXIT
END IF
ls_time = left(mida(ls_val , 9)+"000000",6)
ls_time = left(ls_time,2)+":"+mid(ls_time,3,2)+":" +mid(ls_time,5,2)
IF not isTime(ls_time) THEN
as_error += "第"+String(ll_cc)+"行,位置:"+String(li_pos)+",長度:"+&
String(ll_collimit[li_Col])+"無法轉換Datetime~r~n"
lb_fin = false
EXIT
END IF
ldt_1 = Datetime(date(ls_date),time(ls_time))
ELSE
SetNull(ldt_1)
END IF
ads_dest.SetItem(ll_new , li_col , ldt_1)
Case "date"
//日期
IF trim(ls_val) <> "" THEN
ls_date = left(ls_val,4)+"/"+mid(ls_val,5,2)+"/"+mid(ls_val,7,2)
IF not isDate(ls_date) THEN
as_error += "第"+String(ll_cc)+"行,位置:"+String(li_pos)+",長度:"+&
String(ll_collimit[li_Col])+"無法轉換Date~r~n"
lb_fin = false
EXIT
END IF
ELSE
SetNull(ls_date)
END IF
ads_dest.SetItem(ll_new , li_col , Date(ls_date))
Case "time"
//時間
IF trim(ls_val) <> "" THEN
ls_time = left(ls_val+"000000",6)
ls_time = left(ls_time,2)+":"+mid(ls_time,3,2)+":"+mid(ls_time,5,2)
IF not isTime(ls_time) THEN
as_error += "第"+String(ll_cc)+"行,位置:"+String(li_pos)+",長度:"+&
String(ll_collimit[li_Col])+"無法轉換Time~r~n"
lb_fin = false
EXIT
END IF
ELSE
SetNull(ls_time)
END IF
ads_dest.SetItem(ll_new , li_col , Time(ls_time))
Case "long" ,"ulong"
//整數
IF trim(ls_val) = "" THEN
SetNull(ls_val)
END IF
ads_dest.SetItem(ll_new , li_col , long(ls_val))
Case "decimal"
//數值
IF trim(ls_val) = "" THEN
SetNull(ls_val)
END IF
ads_dest.SetItem(ll_new , li_col , dec(ls_val))
Case "real"
//浮點數
IF trim(ls_val) = "" THEN
SetNull(ls_val)
END IF
ads_dest.SetItem(ll_new , li_col , real(ls_val))
End Choose
//定位點移到下一個指定位置
li_pos = li_pos + ll_collimit[li_Col]
NEXT
//處理錯誤跳出,未完成者取消此筆ROW
IF lb_fin = false THEN
ads_dest.rowsDisCard(ll_new , ll_new , Primary!)
END IF
loop
//關閉檔案
FileClose(li_file)
//回傳處理行數
Return ll_cc
與之前轉出EDI作法有點不一樣的地方,是在於取得 DataObject 的 DataWindow 欄位屬性時,我直接使用了幾個陣列(ll_collimit[]、ls_colname[]、ls_coltype[])來儲存,上次是使用一個structure來儲存,結果是相同,寫法不同,可以提供一個比較參考。
其次,這次轉入EDI檔案時欄位長度的參考,我是設計在每個欄位的 Edit.Limit 上,所以這個Function 使用時只要設計好 DataWindow 的模型就很好用了。
其次,使用上需要特別注意的地方是[日期時間]、[日期]、[時間]的轉換方式,我的設計上是假設EDI上的欄位日期是西元年的 YYYYMMDDHHMMSS 的格式的,所以 Datetime
欄位的 Limit 可以設定 8、10、14、16碼的,怎麼說呢?
假設日期欄來源資料為 YYMMDDHHMM的話,後面SS會自動補上00
例如:201208091325 -> 20120809132500 -> 2012/8/9 13:25:00
例如:2012080913 -> 20120809130000 -> 2012/8/9 13:00:00
如此可以簡化不少操作
倘偌需要更多格式的日期轉換就需要改寫轉換規則就可以了。
留言