我想用马提尼打印CSV数据到输出。目前,我始终使用r.JSON(200, somestruct)
r
来自render.Render
的{{1}}。
现在我有一块结构,我想将它们打印为CSV(将一个结构的每个字段字符串化并在一行打印一个结构)。
目前,我这样做:
github.com/martini-contrib
但我不喜欢我这样做的原因如下:
r.Data(200, []byte("id,Latitude,Longitude\n"))
for _, packet := range tour.Packets {
r.Data(200, []byte(strconv.FormatInt(packet.Id, 10)+","+strconv.FormatFloat(packet.Latitude, 'f', 6, 64)+","+strconv.FormatFloat(packet.Longitude, 'f', 6, 64)+"\n"))
}
http: multiple response.WriteHeader calls
,ìnt64
或float64
。如何以更简单的方式实施CSV导出选项?
答案 0 :(得分:-1)
使用标准库。没有反射就没有通用的解决方案,但你可以简化它。
func handler(rw http.ResponseWriter) {
rw.Header().Add("Content-Type", "text/csv")
wr := csv.NewWriter(rw)
err := wr.Write([]string{"id", "Latitude", "Longitude"})
if err != nil {
...
}
for _, packet := range tour.Packets {
err := wr.Write([]string{
strconv.FormatInt(packet.Id, 10),
strconv.FormatFloat(packet.Latitude, 'f', 6, 64),
strconv.FormatFloat(packet.Longitude, 'f', 6, 64),
})
if err != nil {
...
}
}
}
如果您需要任何结构的通用解决方案,则需要反映。 见here。
// structToStringSlice takes a struct value and
// creates a string slice of all the values in that struct
func structToStringSlice(i interface{}) []string {
v := reflect.ValueOf(i)
n := v.NumField()
out := make([]string, n)
for i := 0; i < n; i++ {
field := v.Field(i)
switch field.Kind() {
case reflect.String:
out[i] = field.String()
case reflect.Int:
out[i] = strconv.FormatInt(field.Int(), 10)
// add cases here to support more field types.
}
}
return out
}
// writeToCSV prints a slice of structs as csv to a writer
func writeToCSV(w io.Writer, i interface{}) {
wr := csv.NewWriter(w)
v := reflect.ValueOf(i)
// Get slice's element type (some unknown struct type)
typ := v.Type().Elem()
numFields := typ.NumField()
fieldSet := make([]string, numFields)
for i := 0; i < numFields; i++ {
fieldSet[i] = typ.Field(i).Name
}
// Write header row
wr.Write(fieldSet)
// Write data rows
sliceLen := v.Len()
for i := 0; i < sliceLen; i++ {
wr.Write(structToStringSlice(v.Index(i).Interface()))
}
wr.Flush()
}
那么你的例子就是:
func handler(rw http.ResponseWriter) {
....
writeToCSV(rw, tour.Packets)
}
我写的函数只适用于int或string字段。通过在structToStringSlice中向交换机添加案例,您可以轻松地将其扩展到更多类型。有关另一个Kinds
的反映文档,请参见here。