在我的一個業餘專案中建立資料轉換實用程式時,我需要將 JSON 格式的檔案轉換為 CSV 格式。我遇到了一個棘手的問題,花了近一個小時進行調試才確定根本原因。
這個過程應該很簡單,包括三個主要步驟:
func JsonToCSV(data *SrcSheet) { // Create file name in a format like "email_241030172647.csv" (email_yymmddhhmmss.csv) fName := fileName() // Create file f, err := os.Create(fName) if err != nil { log.Println("Unable to create file", err) return } defer f.Close() // Closing to release resources w := csv.NewWriter(f) // Initializing CSV writer // Add header header := []string{"email", "provider", "added_on"} if err = w.Write(header); err != nil { log.Println("Unable to write header", err) return } count := 0 for domain, elm := range data.Email { if err := w.Write(newRecord(domain, elm)); err != nil { log.Println("Unable to add new record", domain, err) return } else { count++ } } log.Println("Number of records written =", count) } func newRecord(email string, e *SrcElements) []string { if e == nil { return nil } DBFormat := "2006-01-02 15:04:05.000" addedOn := time.Now().UTC().Format(DBFormat) r := []string{email, e.Provider, addedOn} return r }
程式碼很簡單:建立一個具有特定名稱格式的新文件,推遲其關閉,初始化 CSV 編寫器,然後開始寫入該文件。超簡單吧?
步驟 1 和 2 效果很好,所以省略了。讓我們將焦點轉移到步驟 3,其中發生了意外的情況:CSV 輸出僅包含 65,032 筆記錄,這意味著缺少 310 筆記錄。
為了排除故障,我嘗試了僅使用 7 個 JSON 元素(而不是 65,032 個)的程式碼。令人驚訝的是,CSV 檔案中根本沒有寫入任何內容!
我仔細檢查了一些簡單的錯誤,例如缺少文件關閉,但一切看起來都很好。然後我重試了完整的 65,032 個元素,希望能獲得更多線索。這時我發現不僅少了310筆記錄,最後一筆記錄也不完整。
65030 adam@gmail.com, gmail, 2023-03-17 15:04:05.000 65031 jac@hotmail.com, hotmail, 2023-03-17 15:04:05.000 65032 nancy@xyz.com, hotmail, 2023-03-
這是進步——我現在可以縮小問題範圍並專注於 w.Write(newRecord(domain, elm)),特別是 w.Write(...) 方法。我查了文檔,找到原因:
...寫入會被緩衝,因此最終必須呼叫 [Writer.Flush] 以確保記錄寫入底層 io.Writer ...
我忘記呼叫 w.Flush()。這是有道理的,因為從效能角度來看,CSV 編寫器會緩衝寫入,而不是每次呼叫 w.Write() 時執行 I/O 操作。透過緩衝數據,它減少了 I/O 負載,並在最後調用 w.Flush() 確保緩衝區中的任何剩餘數據都寫入檔案。
這是修正後的程式碼:
... f, err := os.Create(fName) if err != nil { log.Println("Unable to create file", err) return } defer f.Close() w := csv.NewWriter(f) defer w.Flush() // Add header header := []string{"email", "provider", "added_on"} ...
為了確認,我檢查了 bufio.go 原始碼,發現預設緩衝區大小為 4K。在 WriteRune(...) 方法中,您將看到每當緩衝區達到其限制時它就會呼叫 Flush。
就這些了!我希望你喜歡閱讀。我傾向於從錯誤中學到很多東西——無論是我的還是別人的。即使沒有立即解決辦法,發現錯誤的方法也可以幫助我避免將來陷入類似的陷阱。這就是為什麼我想分享這個經驗!
以上是遺失記錄之謎:在 Go 中調試 JSON 到 CSV 的轉換的詳細內容。更多資訊請關注PHP中文網其他相關文章!