首頁  >  文章  >  後端開發  >  遺失記錄之謎:在 Go 中調試 JSON 到 CSV 的轉換

遺失記錄之謎:在 Go 中調試 JSON 到 CSV 的轉換

Barbara Streisand
Barbara Streisand原創
2024-11-02 09:31:31932瀏覽

The Mystery of Missing Records: Debugging a JSON-to-CSV Transformation in Go

在我的一個業餘專案中建立資料轉換實用程式時,我需要將 JSON 格式的檔案轉換為 CSV 格式。我遇到了一個棘手的問題,花了近一個小時進行調試才確定根本原因。

這個過程應該很簡單,包括三個主要步驟:

  1. 開啟 JSON 檔案
  2. 將該 JSON 檔案解析為特定結構
  3. 將資料寫入 CSV 文件 首先,讓您了解一下,JSON 是一個包含 65,342 個元素的陣列。
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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn