2014年5月20日 星期二

powerbuilder匯入(讀取)檔案時的注意技巧

先看看下面一段程式碼:

ls_path = "C:\inetpub\ftproot\upload\custOrder.txt"
do while FileExists(ls_path)
   yield()
loop
dw_1.importFile(text!,ls_path)
// next , processing dw1 row data
FileDelete(ls_path)

這是一個讓客戶用FTP上傳檔案後,並讀取檔案內容,處理後便把檔案刪除的作業,邏輯上是合理的,絕大多數的情況下也是沒有問題的。

但是偶爾發生了客戶資料沒有處理的問題,客戶也說明明就上傳成功了,FTP傳輸日誌有出現傳輸成功的指令,但,為什麼卻沒有處理到資料?

這段程式碼持續使用迴圈檢查檔案是否生成,只要檔案出現就進行讀取。

這看起來沒有錯,但是卻常常發生檔案讀出空白或是不完整的情況。

為什麼會這樣?
最大問題出在『時間差』,也就是檔案名稱產生的時間和檔案內容產生的時間有時間差異存在。檔案越大這個問題越明顯!

因為檔案系統會先生成檔案名稱並賦予記憶體指標(檔案內容緩衝區),當檔案指標被應用程式Close時,OS才會把檔案內容緩衝區的內容,寫到磁碟機上。



這個動作是作業系統為了加快檔案處理的速度而設計,緩衝區大小預設為磁碟sector大小,也就是說你的磁碟如果 sector 是 512K ,預設緩衝區就是 512K,若是sector 為 4096K,緩衝區就是 4096K。然而這個緩衝區可以依照應用程式去要求作業系統調整的,基本的原則是sector的倍數。
相關參考:微軟檔案緩存資料緩存定義

因此,要如何判斷得知檔案是否已經寫入完成,並且可以讀取呢?

目前我測試有兩種方法可以使用:
一、檔案大小法:如果運作的磁碟機 Sector 是 512K,而你非常肯定你的檔案大小絕對不會超過512K,那很好,除了取得檔案名稱外另外加判斷檔案大小,只要取得的檔案大小超過0,就代表檔案已經從緩衝區 Flush或Close 了,這樣就可以讀取了。

ls_path = "C:\inetpub\ftproot\upload\custOrder.txt"
do while FileExists(ls_path)
   yield()
loop

if FileLength(ls_path) > 0 tehn
   dw_1.importFile(text!,ls_path)
   // next , processing dw1 row data
   FileDelete(ls_path)
else
  //go next perpare reading loop cycle
end if

二、檔案鎖定法:利用獨佔式開啟檔案方式,確認該檔案是否已經被FTP釋放(Close)掉。

ls_path = "C:\inetpub\ftproot\upload\custOrder.txt"
do while FileExists(ls_path)
   yield()
loop

/*利用R/W lock來開啟檔案,開啟成功就代表檔案已經釋放,開啟失敗,代表檔案還被FTP使用中*/
li_file = FileOpen(ls_path,StreamMode,Read!,LockReadWrite!)
if li_file > 0 tehn
   // 這裡使用pb10版本提供的ReadEx比較方便,若是舊版,請記得使用迴圈讀取檔案全部內容
   ll_byte = FileReadEx(li_file,ls_data)
   FileClose(li_file)
   // 改用ImportString
   dw_1.importString(text!,ls_data)
   // next , processing dw1 row data
   FileDelete(ls_path)
else
  //go next perpare reading loop cycle
end if

請注意,範例裡的測試檔案存在的迴圈沒有停止機制,如果您要實作,記得要加上停止機制以免當檔案一直不出現就會出現的無限迴圈


0 個回應: