将结构体写入CSV文件

huangapple go评论86阅读模式
英文:

Write struct to csv file

问题

将结构体转储到CSV文件的惯用方式是什么?我在一个函数中,该函数接收一个作为interface{}传递的结构体:

func decode_and_csv(my_response *http.Response, my_struct interface{})

为什么使用interface{}?因为从JSON中读取数据时可能返回几种不同的结构体,所以我试图编写一个足够通用的函数。

这是我的类型的一个示例:

type Location []struct {
    Name                   string `json:"Name"`
    Region                 string `json:"Region"`
    Type                   string `json:"Type"`
}

请注意,我只提供翻译服务,不会回答关于翻译内容的问题。

英文:

What is an idiomatic golang way to dump the struct into a csv file provided? I am inside a func where my struct is passed as interface{}:

func decode_and_csv(my_response *http.Response, my_struct interface{})

Why interface{}? - reading data from JSON and there could be a few different structs returned, so trying to write a generic enough function.

an example of my types:

type Location []struct {
    Name                   string `json: "Name"`
    Region                 string `json: "Region"`
    Type                   string `json: "Type"`
}

答案1

得分: 36

如果你使用具体类型会更容易一些。你可能会想要使用encoding/csv包,这里有一个相关的示例:https://golang.org/pkg/encoding/csv/#example_Writer

正如你所看到的,Write方法期望一个[]string类型的参数,所以为了生成这个参数,你需要做以下两种方法之一:1)提供一个辅助方法,或者2)使用反射来获取my_struct的字段。个人而言,我更喜欢第一种方法,但这取决于你的需求。如果你选择第二种方法,你可以将结构体的所有字段作为列标题,然后迭代字段,获取每个字段的值,在循环中使用append将它们添加到一个[]string中,然后在循环外将其传递给Write方法。

对于第一种选项,我会在每个类型上定义一个ToSlice方法,然后创建一个名为CsvAble的接口,要求实现ToSlice方法。在你的方法中,将类型改为my_struct CsvAble,而不是使用空接口,然后你可以直接在my_struct上调用ToSlice方法,并将返回值传递给Write方法。你可以让ToSlice方法返回列标题(这意味着你将得到一个[][]string,需要迭代外部维度,将每个[]string传递给Write方法),或者你可以要求另一个方法满足接口,比如GetHeaders方法,它返回一个[]string,表示列标题。如果是这样的话,你的代码将如下所示:

w := csv.NewWriter(os.Stdout)
headers := my_struct.GetHeaders()
values := my_struct.ToSlice()
if err := w.Write(headers); err != nil {
    // 写入失败,做一些处理
}
if err := w.Write(values); err != nil {
    // 写入失败,做一些处理
}

如果这不太清楚,请告诉我,我可以提供两种方法中的任何一种的代码示例。

英文:

It would be a lot easier if you used a concrete type. You'll probably want to use the encoding/csv package, here is a relevant example; https://golang.org/pkg/encoding/csv/#example_Writer

As you can see, the Write method is expecting a []string so in order to generate this, you'll have to either 1) provide a helper method or 2) reflect my_struct. Personally, I prefer the first method but it depends on your needs. If you want to go route two you can get all the fields on the struct an use them as the column headers, then iterate the fields getting the value for each, use append in that loop to add them to a []string and then pass it to Write out side of the loop.

For the first option, I would define a ToSlice or something on each type and then I would make an interface call it CsvAble that requires the ToSlice method. Change the type in your method my_struct CsvAble instead of using the empty interface and then you can just call ToSlice on my_struct and pass the return value into Write. You could have that return the column headers as well (meaning you would get back a [][]string and need to iterate the outer dimension passing each []string into Write) or you could require another method to satisfy the interface like GetHeaders that returns a []string which is the column headers. If that were the case your code would look something like;

w := csv.NewWriter(os.Stdout)
headers := my_struct.GetHeaders()
values := my_struct.ToSlice()
if err := w.Write(headers); err != nil {
    //write failed do something
}
if err := w.Write(values); err != nil {
    //write failed do something
}

If that doesn't make sense let me know and I can follow up with a code sample for either of the two approaches.

huangapple
  • 本文由 发表于 2015年10月27日 07:05:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/33357156.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定