Playground
type Student struct {
Name string `csv:"name"`
Birthdate time.Time `csv:"birthdate"`
Address string `csv:"address,omitempty"`
}
students := []Student{
{Name: "jerry", Birthdate: time.Date(1990, time.January, 1, 0, 0, 0, 0, time.UTC), Address: "tokyo"},
{Name: "tom", Birthdate: time.Date(1989, time.November, 11, 0, 0, 0, 0, time.UTC), Address: "new york"},
}
data, err := csvlib.Marshal(students)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(data))
// Output:
// name,birthdate,address
// jerry,1990-01-01T00:00:00Z,tokyo
// tom,1989-11-11T00:00:00Z,new york
No header mode
Playground
type Student struct {
Name string `csv:"name"`
Birthdate time.Time `csv:"birthdate"`
Address string `csv:"address,omitempty"`
}
students := []Student{
{Name: "jerry", Birthdate: time.Date(1990, time.January, 1, 0, 0, 0, 0, time.UTC), Address: "tokyo"},
{Name: "tom", Birthdate: time.Date(1989, time.November, 11, 0, 0, 0, 0, time.UTC), Address: "new york"},
}
data, err := csvlib.Marshal(students, func(cfg *csvlib.EncodeConfig) {
cfg.NoHeaderMode = true
})
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(data))
// Output:
// jerry,1990-01-01T00:00:00Z,tokyo
// tom,1989-11-11T00:00:00Z,new york
- Postprocessor functions will be called after Go values are encoded into CSV string.
Playground
type Student struct {
Name string `csv:"name"`
Age int `csv:"age"`
Address string `csv:"address,omitempty"`
}
students := []Student{
{Name: "jerry ", Age: 20, Address: "tokyo"},
{Name: " tom ", Age: 19, Address: "new york"},
}
data, err := csvlib.Marshal(students, func(cfg *csvlib.EncodeConfig) {
cfg.ConfigureColumn("name", func(cfg *csvlib.EncodeColumnConfig) {
cfg.PostprocessorFuncs = []csvlib.ProcessorFunc{csvlib.ProcessorTrim, csvlib.ProcessorUpper}
})
})
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(data))
// Output:
// name,age,address
// JERRY,20,tokyo
// TOM,19,new york
- To skip encoding a column, you can omit the
csv
tag from the struct field or use csv:"-"
. You can also use an equivalent configuration option for the column.
Playground
type Student struct {
Name string `csv:"name"`
Age int `csv:"-"`
Address string `csv:"address,omitempty"`
}
students := []Student{
{Name: "jerry", Age: 20, Address: "tokyo"},
{Name: "tom", Age: 19, Address: "new york"},
}
data, err := csvlib.Marshal(students, func(cfg *csvlib.EncodeConfig) {
cfg.ConfigureColumn("address", func(cfg *csvlib.EncodeColumnConfig) {
cfg.Skip = true
})
})
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(data))
// Output:
// name
// jerry
// tom
- Fixed inline columns are represented by an inner struct.
prefix
can be set for inline columns.
Playground
type Marks struct {
Math int `csv:"math"`
Chemistry int `csv:"-"`
Physics int `csv:"physics"`
}
type Student struct {
Name string `csv:"name"`
Age int `csv:"age,omitempty"`
Address string `csv:"address,optional"`
Marks Marks `csv:"marks,inline,prefix=mark_"`
}
students := []Student{
{Name: "jerry", Age: 20, Address: "tokyo", Marks: Marks{Math: 9, Chemistry: 8, Physics: 7}},
{Name: "tom", Age: 0, Address: "new york", Marks: Marks{Math: 7, Chemistry: 8, Physics: 9}},
}
data, err := csvlib.Marshal(students)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(data))
// Output:
// name,age,address,mark_math,mark_physics
// jerry,20,tokyo,9,7
// tom,,new york,7,9
- Dynamic inline columns are represented by an inner struct with variable number of columns.
prefix
can also be set for them.
Playground
type Student struct {
Name string `csv:"name"`
Age int `csv:"age,omitempty"`
Address string `csv:"address,optional"`
Marks csvlib.InlineColumn[int] `csv:"marks,inline,prefix=mark_"`
}
marksHeader := []string{"math", "chemistry", "physics"}
students := []Student{
{Name: "jerry", Age: 20, Address: "tokyo", Marks: csvlib.InlineColumn[int]{Header: marksHeader, Values: []int{9, 8, 7}}},
{Name: "tom", Age: 0, Address: "new york", Marks: csvlib.InlineColumn[int]{Header: marksHeader, Values: []int{7, 8, 9}}},
}
data, err := csvlib.Marshal(students)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(data))
// Output:
// name,age,address,mark_math,mark_chemistry,mark_physics
// jerry,20,tokyo,9,8,7
// tom,,new york,7,8,9
- Any user custom type can be decoded by implementing either
encoding.TextMarshaler
or csvlib.CSVMarshaler
or both. csvlib.CSVMarshaler
has higher priority.
Playground
type BirthDate time.Time
func (d BirthDate) MarshalCSV() ([]byte, error) {
return []byte(time.Time(d).Format("2006-01-02")), nil // RFC3339
}
type Student struct {
Name string `csv:"name"`
Birthdate BirthDate `csv:"birthdate"`
Address string `csv:"address,omitempty"`
}
students := []Student{
{Name: "jerry", Birthdate: BirthDate(time.Date(1990, time.January, 1, 0, 0, 0, 0, time.UTC)), Address: "tokyo"},
{Name: "tom", Birthdate: BirthDate(time.Date(1989, time.November, 11, 0, 0, 0, 0, time.UTC)), Address: "new york"},
}
data, err := csvlib.Marshal(students)
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(data))
// Output:
// name,birthdate,address
// jerry,1990-01-01,tokyo
// tom,1989-11-11,new york
- By default, the encoder uses comma as the delimiter, if you want to encode custom one, use
csv.Writer
from the built-in package encoding/csv
as the input writer.
Playground
type Student struct {
Name string `csv:"name"`
Age int `csv:"age"`
Address string `csv:"address"`
}
students := []Student{
{Name: "jerry", Age: 20, Address: "tokyo"},
{Name: "tom", Age: 19, Address: "new york"},
}
var buf bytes.Buffer
writer := csv.NewWriter(&buf)
writer.Comma = '\t'
err := csvlib.NewEncoder(writer).Encode(students)
if err != nil {
fmt.Println("error:", err)
}
writer.Flush()
fmt.Println(buf.String())
// Output:
// name age address
// jerry 20 tokyo
// tom 19 new york
Playground
type Student struct {
Name string `csv:"name"`
Age int `csv:"age"`
Address string `csv:"address"`
}
students := []Student{
{Name: "jerry", Age: 20, Address: "tokyo"},
{Name: "tom", Age: 19, Address: "new york"},
}
var buf bytes.Buffer
writer := csv.NewWriter(&buf)
encoder := csvlib.NewEncoder(writer)
for _, student := range students {
if err := encoder.EncodeOne(student); err != nil {
fmt.Println("error:", err)
break
}
}
encoder.Finish()
writer.Flush()
fmt.Println(buf.String())
// Output:
// name,age,address
// jerry,20,tokyo
// tom,19,new york
Header localization
- This functionality allows to encode CSV data with header translated into a specific language.
Playground
// Sample localization data (you can define them somewhere else such as in a json file)
var (
mapLanguageEn = map[string]string{
"name": "name",
"age": "age",
"address": "address",
}
mapLanguageVi = map[string]string{
"name": "tên",
"age": "tuổi",
"address": "địa chỉ",
}
)
func localizeViVn(k string, params csvlib.ParameterMap) (string, error) {
return mapLanguageVi[k], nil
}
func localizeEnUs(k string, params csvlib.ParameterMap) (string, error) {
return mapLanguageEn[k], nil
}
type Student struct {
Name string `csv:"name"`
Age int `csv:"age"`
Address string `csv:"address,omitempty"`
}
students := []Student{
{Name: "jerry", Age: 20, Address: "tokyo"},
{Name: "tom", Age: 19, Address: "new york"},
}
data, err := csvlib.Marshal(students, func(cfg *csvlib.EncodeConfig) {
cfg.LocalizeHeader = true
cfg.LocalizationFunc = localizeViVn
})
if err != nil {
fmt.Println("error:", err)
}
fmt.Println(string(data))
// Output:
// tên,tuổi,địa chỉ
// jerry,20,tokyo
// tom,19,new york