Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Misteri Rekod Hilang: Menyahpepijat Transformasi JSON-ke-CSV dalam Go

Misteri Rekod Hilang: Menyahpepijat Transformasi JSON-ke-CSV dalam Go

Barbara Streisand
Barbara Streisandasal
2024-11-02 09:31:31932semak imbas

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

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:

  1. Buka fail JSON
  2. Uraikan fail JSON itu ke dalam struktur tertentu
  3. Tulis data pada fail CSV Pertama, untuk memberi anda idea, JSON ialah tatasusunan dengan 65,342 elemen.
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!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn