使用golang将多列写入csv文件

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

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        |

huangapple
  • 本文由 发表于 2022年5月10日 15:39:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/72182387.html
匿名

发表评论

匿名网友

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

确定