gocsv

repository·master·Indexed 24 days ago

https://github.com/gocarina/gocsv

A Go package for serialization and deserialization of CSV data using struct tags. It provides functionality to marshal Go structs to CSV strings or files and unmarshal CSV data into structs, slices, or maps. Features include support for nested structs, custom converters via MarshalCSV and UnmarshalCSV methods, streaming via channels, callback processing, and thread-safe writing with SafeCSVWriter.

Tokens
4K
Snippets
12
Records
31
Agent score
72%

What's inside gocsv

  1. Handle nested structs in CSV

    master

    By default, gocsv prefixes nested struct fields with the parent field's name (e.g., Parent.ChildField). To inline a nested struct and use its fields directly as top-level columns without a prefix, use the csv:"." tag on the nested field.

    type Foo struct {
    	B Bar `csv:"."` // Fields in Bar will be 'a, b' instead of 'B.a, B.b'
    	X int `csv:"x"` 
    }
    
    type Bar struct {
    	A int `csv:"a"` 
    	B int `csv:"b"` 
    }
  2. Implement customizable converters

    master

    You can define custom serialization and deserialization logic for specific types by implementing the MarshalCSV() (string, error) and UnmarshalCSV(csv string) error methods on your type. This allows you to handle custom date formats or complex data transformations during the CSV process.

    type DateTime struct {
    	time.Time
    }
    
    // Convert the internal date as CSV string
    func (date *DateTime) MarshalCSV() (string, error) {
    	return date.Time.Format("20060201"), nil
    }
    
    // Convert the CSV string as internal date
    func (date *DateTime) UnmarshalCSV(csv string) (err error) {
    	date.Time, err = time.Parse("20060201", csv)
    	return err
    }
  3. Unmarshal CSV data into a slice of structs

    master
    To deserialize CSV data into a slice of structs, use the Unmarshal pattern (implied by the internal readTo logic). The target must be a pointer to a slice or an array of structs. The structs must contain csv tags corresponding to the CSV headers.
  4. Marshal Go structs to CSV string or file

    master

    To convert a slice of structs into a CSV string, use gocsv.MarshalString. To save the data directly to a file, use gocsv.MarshalFile.

    // Get all clients as CSV string
    csvContent, err := gocsv.MarshalString(&clients)
    
    // Use this to save the CSV back to the file
    err = gocsv.MarshalFile(&clients, clientsFile)
  5. Unmarshal CSV data into Go structs

    master

    Use gocsv.UnmarshalFile to load CSV data from an os.File into a slice of pointers to a struct. Use struct tags with the csv key to map CSV column headers to struct fields. To ignore a field, use the csv:"-" tag.

    type Client struct {
    	Id            string `csv:"client_id"` 
    	Name          string `csv:"client_name"` 
    	Age           string `csv:"client_age"` 
    	NotUsedString string `csv:"-"` 
    	NotUsedStruct NotUsed `csv:"-"` 
    }
    
    // ...
    
    clients := []*Client{}
    if err := gocsv.UnmarshalFile(clientsFile, &clients); err != nil {
    	panic(err)
    }
  6. Configure custom CSV Reader and Writer

    master

    You can override the default CSV reader and writer behavior using gocsv.SetCSVReader and gocsv.SetCSVWriter. This is useful for changing delimiters (e.g., using a pipe | or dot .), enabling LazyQuotes, or using gocsv.LazyCSVReader.

    // Configure a custom reader with a pipe delimiter
    gocsv.SetCSVReader(func(in io.Reader) gocsv.CSVReader {
        r := csv.NewReader(in)
        r.Comma = '|'
        return r
    })
    
    // Configure a custom writer with a pipe delimiter
    gocsv.SetCSVWriter(func(out io.Writer) *gocsv.SafeCSVWriter {
        writer := csv.NewWriter(out)
        writer.Comma = '|'
        return gocsv.NewSafeCSVWriter(writer)
    })
  7. Configure CSV Tagging and Normalization

    master

    You can customize how gocsv identifies struct fields and how it compares headers to struct tags.

    Global Configuration Variables:

    • TagName: The key in the struct tag to scan (default: "csv").
    • TagSeparator: The separator for multiple tags in a single field (default: ",").
    • FieldsCombiner: The separator used to combine parent and child structs for nested fields (default: ".").
    • FailIfUnmatchedStructTags: If true, an error is returned if a struct tag does not match a CSV header.
    • FailIfDoubleHeaderNames: If true, an error is returned if the CSV contains duplicate header names.
    • ShouldAlignDuplicateHeadersWithStructFieldOrder: If true, duplicate headers are aligned based on their order in the struct definition.

    Header Normalization: To allow case-insensitive matching or to handle character differences (like - vs _), use SetHeaderNormalizer.

    // Example: Case-insensitive header matching
    gocsv.SetHeaderNormalizer(func(s string) string {
    	return strings.ToLower(s)
    })
  8. Use SafeCSVWriter for thread-safe CSV writing

    master

    The SafeCSVWriter provides a thread-safe wrapper around the standard library's *csv.Writer. It uses a sync.Mutex to ensure that concurrent calls to Write and Flush do not cause race conditions or data corruption when multiple goroutines attempt to write to the same CSV destination simultaneously.

    To use it, wrap an existing *csv.Writer using NewSafeCSVWriter(original).

  9. Create a SimpleDecoder from a CSV reader

    master
    Use NewSimpleDecoderFromCSVReader to create a SimpleDecoder from an existing CSVReader. This decoder can be used with the UnmarshalDecoder* family of functions to deserialize CSV data into Go structs. Note that encoding/csv.Reader implements the CSVReader interface and can be passed directly.
  10. Customize CSV Reader and Writer

    master

    You can override the default CSV reader and writer used by the Marshal and Unmarshal functions.

    Customizing the Writer: Use SetCSVWriter(csvWriter func(io.Writer) *SafeCSVWriter) to provide your own writer factory. The default is DefaultCSVWriter, which uses csv.NewWriter wrapped in a SafeCSVWriter.

    Customizing the Reader: Use SetCSVReader(csvReader func(io.Reader) CSVReader) to provide your own reader factory.

    • DefaultCSVReader(in io.Reader): Returns a standard csv.NewReader.
    • LazyCSVReader(in io.Reader): Returns a reader with LazyQuotes and TrimLeadingSpace enabled.
  11. Read a row and capture unmatched columns with ReadUnmatched

    master
    If your CSV contains columns that do not map to any fields in your Go struct, use ReadUnmatched(). This method returns the unmarshalled struct and a map[string]string containing the header names and values of the columns that were not matched to struct fields.