英文:
Writing multiple columns in a csv file using golang
问题
我正在尝试编写一个CSV文件,可以有1到n列。目前我的数据已经正确写入,只是它们都写在同一列上。
我希望有这样的结果:
名称|描述|生产商
name1|desc1|false
name2|desc2|true
name3|desc3|false
这是我的代码,其中一小部分是一个switch语句:
case "companies":
var respToolCompanies entrepriseTool.CompaniesResponse
if jsonErr := json.Unmarshal(resByt, &respToolCompanies); jsonErr != nil {
log.Fatalf("unmarshal: %s", jsonErr)
}
for _, mapping := range mappings {
writeHeader(csvwriter, mapping)
for _, company := range respToolCompanies.Companies {
writeDataAccordinglyToFieldType(mapping, company, csvwriter)
}
csvwriter.Flush()
}
writeDataAccordinglyToFieldType函数:
func writeDataAccordinglyToFieldType(mapping ExportmappingsModel, entities interface{}, csvwriter *csv.Writer) {
switch mapping.SourceColType.String {
case "string":
field := extractFieldValue(entities, mapping)
writeFieldToBuffer(csvwriter, field.String())
case "number":
field := extractFieldValue(entities, mapping)
valInt := field.Int()
str := strconv.Itoa(int(valInt))
writeFieldToBuffer(csvwriter, str)
case "bool":
field := extractFieldValue(entities, mapping)
var boolVal string
if field.Bool() {
boolVal = "true"
} else {
boolVal = "false"
}
writeFieldToBuffer(csvwriter, boolVal)
}
}
以及我写入数据的地方:
func writeFieldToBuffer(csvwriter *csv.Writer, field string) {
err := csvwriter.Write([]string{field})
if err != nil {
log.Println("无法写入文件中的行")
}
}
英文:
I'm trying to write a CSV file, I can have 1 to n columns. Currently my data are correctly written except that they are all written on the same column.
I would like to have something like this :
NAME|DESCRIPTION|PRODUCER
name1|desc1|false
name2|desc2|true
name3|desc3|false
Here is my code, a small piece of a switch:
case "companies":
var respToolCompanies entrepriseTool.CompaniesResponse
if jsonErr := json.Unmarshal(resByt, &respToolCompanies); jsonErr != nil {
log.Fatalf("unmarshal: %s", jsonErr)
}
for _, mapping := range mappings {
writeHeader(csvwriter, mapping)
for _, company := range respToolCompanies.Companies {
writeDataAccordinglyToFieldType(mapping, company, csvwriter)
}
csvwriter.Flush()
}
The writeDataAccordinglyToFieldType function:
func writeDataAccordinglyToFieldType(mapping ExportmappingsModel, entities interface{}, csvwriter *csv.Writer) {
switch mapping.SourceColType.String {
case "string":
field := extractFieldValue(entities, mapping)
writeFieldToBuffer(csvwriter, field.String())
case "number":
field := extractFieldValue(entities, mapping)
valInt := field.Int()
str := strconv.Itoa(int(valInt))
writeFieldToBuffer(csvwriter, str)
case "bool":
field := extractFieldValue(entities, mapping)
var boolVal string
if field.Bool() {
boolVal = "true"
} else {
boolVal = "false"
}
writeFieldToBuffer(csvwriter, boolVal)
}
}
And where I write data:
func writeFieldToBuffer(csvwriter *csv.Writer, field string) {
err := csvwriter.Write([]string{field})
if err != nil {
log.Println("Unable to write a line inside the file")
}
}
答案1
得分: 1
csv.Write函数只有在你的字符串切片中有多个元素时才会写入不同的列。目前你是逐个字段地写入,并且使用的切片每次只有一个记录。
我并不是说你必须传递分隔符。相反,一次性填充字符串切片,这样csv.Write会自动迭代切片,并将每个新元素写入新的列。所以将你的逻辑更改为:
err := csvwriter.Write([]string{field})
改为像这样的逻辑:
record := []string{"name1", "desc1", "false"}
if err := csvwriter.Write(record); err != nil {
log.Fatalln("error writing record to file", err)
}
或者你可以使用二维切片来填充整个内容,然后在最后一次性写入所有内容:
records := [][]string{{"name1", "desc1", "false"}, {"name2", "desc2", "false"}}
if err := csvwriter.WriteAll(records); err != nil {
log.Fatalln("error writing record to file", err)
}
英文:
csv.Write will write in different column only when your string slice will have multiple elements .Currently you are writing each field one by one and using a slice that is only having one record at one time
I am not saying that you have to pass the delimiter .Rather populate the string slice all at once so that csv.Write automatically iterates over the slice and write each new element in new column. . So change your logic to change
err := csvwriter.Write([]string{field})
to something like this :
record := []string {"name1" ,"desc1","false"}
if err := csvwriter.Write(record); err != nil {
log.Fatalln("error writing record to file", err)
}
or you can populate the whole thing using the two dimensional slice and then writeall at the end
records := [][]string {{"name1" ,"desc1","false"},{"name2"
,"desc2","false"}}
if err := csvwriter.WriteAll(records); err != nil {
log.Fatalln("error writing record to file", err)
}
答案2
得分: 0
首先要明确的是,Go语言的csv.Writer是用来写入记录的,而记录是一个字符串切片。从csv包文档的示例中可以看出:
records := [][]string{
{"first_name", "last_name", "username"},
{"Rob", "Pike", "rob"},
{"Ken", "Thompson", "ken"},
{"Robert", "Griesemer", "gri"},
}
w := csv.NewWriter(os.Stdout)
for _, record := range records {
if err := w.Write(record); err != nil {
log.Fatalln("error writing record to csv:", err)
}
}
我们可以看到,我们是逐行写入CSV文件的,而不是逐列写入。因此,无论你采用什么解决方案,在调用writer.Write(...)时都必须包含完整的行。
话虽如此,要在结构体和csv.Writer之间进行转换可能会很困难。你是否看过Gocarina的gocsv包?它可以将(我想象的)你的问题简化为以下代码:
import (
"encoding/json"
"os"
"github.com/gocarina/gocsv"
)
type company struct {
Name string `json:"name" csv:"Name"`
Description string `json:"description" csv:"Description"`
Producer bool `json:"producer" csv:"Producer"`
Employees int `json:"employees" csv:"Employees"`
}
var blob = `[
{ "name": "Foo To You", "description": "Selling Foo since before the dinosaurs", "producer": false, "employees": 7 },
{ "name": "Bar Mfg.", "description": "Best makers of Bar, bar none", "producer": true, "employees": 12 }
]`
func main() {
var companies []company
json.Unmarshal([]byte(blob), &companies)
gocsv.Marshal(companies, os.Stdout)
}
可以生成以下CSV(以表格形式标记):
| Name | Description | Producer | Employees |
|------------|----------------------------------------|----------|-----------|
| Foo To You | Selling Foo since before the dinosaurs | false | 7 |
| Bar Mfg. | Best makers of Bar, bar none | true | 12 |
英文:
First things first: Go's csv Writer writes a record, and a record is a slice of strings. Looking at the example from the csv pkg documentation:
records := [][]string{
{"first_name", "last_name", "username"},
{"Rob", "Pike", "rob"},
{"Ken", "Thompson", "ken"},
{"Robert", "Griesemer", "gri"},
}
w := csv.NewWriter(os.Stdout)
for _, record := range records {
if err := w.Write(record); err != nil {
log.Fatalln("error writing record to csv:", err)
}
}
we can see that we write to a CSV file row-by-row, not column-by-column. So any solution you come up with must include a complete row when you call writer.Write(...).
That said, going between a struct and the csv Writer can be difficult. Have you looked at Gocarina's gocsv package? It would reduce (what I imagine to be) your problem down to something like the following:
import (
"encoding/json"
"os"
"github.com/gocarina/gocsv"
)
type company struct {
Name string `json:"name" csv:"Name"`
Description string `json:"description" csv:"Description"`
Producer bool `json:"producer" csv:"Producer"`
Employees int `json:"employees" csv:"Employees"`
}
var blob = `[
{ "name": "Foo To You", "description": "Selling Foo since before the dinosaurs", "producer": false, "employees": 7 },
{ "name": "Bar Mfg.", "description": "Best makers of Bar, bar none", "producer": true, "employees": 12 }
]`
func main() {
var companies []company
json.Unmarshal([]byte(blob), &companies)
gocsv.Marshal(companies, os.Stdout)
}
to produce this CSV (marked-up as a table):
| Name | Description | Producer | Employees |
|------------|----------------------------------------|----------|-----------|
| Foo To You | Selling Foo since before the dinosaurs | false | 7 |
| Bar Mfg. | Best makers of Bar, bar none | true | 12 |
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论