Semasa saya bekerja membina utiliti untuk transformasi data pada salah satu projek sampingan saya, saya perlu menukar fail berformat JSON kepada format CSV. Saya menghadapi isu rumit yang mengambil masa hampir sejam untuk nyahpepijat sebelum mengenal pasti puncanya.
Prosesnya sepatutnya mudah, terdiri daripada tiga langkah utama:
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 }
Kod ini mudah: buat fail baharu dengan format nama tertentu, tangguhkan penutupannya, mulakan penulis CSV dan mula menulis pada fail. Sangat mudah, bukan?
Langkah 1 dan 2 berfungsi dengan baik, jadi tinggalkan mereka. Mari beralih fokus ke langkah 3, apabila sesuatu yang tidak dijangka berlaku: output CSV mengandungi hanya 65,032 rekod, bermakna 310 rekod telah hilang.
Untuk menyelesaikan masalah, saya mencuba kod dengan hanya 7 elemen JSON dan bukannya 65,032. Yang menghairankan, tiada apa pun ditulis pada fail CSV sama sekali!
Saya menyemak semula untuk kesilapan mudah, seperti kehilangan penutupan fail, tetapi semuanya kelihatan baik. Saya kemudian mencuba semula dengan 65,032 elemen penuh, dengan harapan untuk mendapatkan lebih banyak petunjuk. Ketika itulah saya perasan bahawa bukan sahaja 310 rekod hilang, tetapi rekod terakhir juga tidak lengkap.
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-
Ini adalah kemajuan—saya kini boleh mengecilkan isu tersebut dan menumpukan pada w.Write(newRecord(domain, elm)), khususnya kaedah w.Write(...). Saya menyemak dokumentasi dan mendapati sebabnya:
... Tulisan ditimbal, jadi [Writer.Flush] mesti dipanggil untuk memastikan rekod ditulis kepada io.Writer yang mendasari ...
Saya terlupa untuk menghubungi w.Flush(). Ini masuk akal kerana, dari perspektif prestasi, penimbal penulis CSV menulis dan bukannya melaksanakan operasi I/O setiap kali w.Write() dipanggil. Dengan menimbal data, ia mengurangkan beban I/O dan memanggil w.Flush() pada penghujungnya memastikan sebarang baki data dalam penimbal ditulis pada fail.
Berikut ialah kod yang diperbetulkan:
... 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"} ...
Untuk mengesahkan, saya menyemak kod sumber bufio.go dan mendapati saiz penimbal lalai ialah 4K. Dalam kaedah WriteRune(...), anda akan melihat bahawa ia memanggil Flush apabila penimbal mencapai hadnya.
Itu sahaja! Saya harap anda seronok membaca. Saya cenderung untuk belajar banyak daripada kesilapan-sama ada kesilapan saya atau orang lain. Walaupun tiada penyelesaian segera, menemui pendekatan yang salah membantu saya mengelakkan perangkap yang sama pada masa hadapan. Itulah sebabnya saya ingin berkongsi pengalaman ini!
Atas ialah kandungan terperinci Misteri Rekod Hilang: Menyahpepijat Transformasi JSON-ke-CSV dalam Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!