Go语言生成的csv文件用excel表打开是乱码的原理及解决办法

74 阅读1分钟

问题复现

package main

import (
   "encoding/csv"
   "log"
   "os"
   "strconv"
)

func main() {
   // 创建文件
   file, _ := os.Create("test.csv")
   defer file.Close()

   // 创建一个csv.Writer对象
   writer := csv.NewWriter(file)
   defer writer.Flush()

   // 写入数据到CSV文件中
   data := [][]string{
      {"序号", "姓名", "年龄"},
      {"1", "张三", strconv.Itoa(25)},
      {"2", "李四", strconv.Itoa(30)},
      {"3", "王五", strconv.Itoa(28)},
   }
   writer.WriteAll(data)

   writer.Flush()
   if err := writer.Error(); err != nil {
      log.Fatal(err)
   }
}

通过这个代码生成的csv文件,由于存在中文字符串,所以使用excel表打开是乱码的。 具体可以通过developer.aliyun.com/article/539… 来告知excel对应的编码格式从而打开不是乱码的文件。

原因

这是因为golang是使用utf-8对csv文件进行编码的,但是excel默认是使用ANSI编码格式来打开文件的,excel表无法打开即识别utf-8编码的文件,所以就出现了乱码。

解决办法

知道了原因,就能知道解决办法了,通过测试,发现excel表能打开即识别utf-8 bom、GBK(向下兼容ANSI)、ANSI等编码的文件,所以只要在写入文件时改为对应的编码方式就好了。

解决办法一:使用utf-8 bom编码

只需要在文件开头写入对应的字节顺序标记就好了。

package main

import (
   "encoding/csv"
   "log"
   "os"
   "strconv"
)

func main() {
   // 创建文件
   file, _ := os.Create("test.csv")
   defer file.Close()

   //标记为utf-8 bom编码
   file.WriteString("xEFxBBxBF")

   // 创建一个csv.Writer对象
   writer := csv.NewWriter(file)
   defer writer.Flush()

   // 写入数据到CSV文件中
   data := [][]string{
      {"序号", "姓名", "年龄"},
      {"1", "张三", strconv.Itoa(25)},
      {"2", "李四", strconv.Itoa(30)},
      {"3", "王五", strconv.Itoa(28)},
   }
   writer.WriteAll(data)

   writer.Flush()
   if err := writer.Error(); err != nil {
      log.Fatal(err)
   }
}

解决办法二:使用GBK编码

package main

import (
   "encoding/csv"
   "log"
   "os"
   "strconv"

   "golang.org/x/text/encoding/simplifiedchinese"
   "golang.org/x/text/transform"
)

func main() {
   // 创建文件
   file, _ := os.Create("test.csv")
   defer file.Close()

   // 创建一个csv.Writer对象 (使用gbk编码)
   writer := csv.NewWriter(transform.NewWriter(file, simplifiedchinese.GBK.NewEncoder()))
   defer writer.Flush()

   // 写入数据到CSV文件中
   data := [][]string{
      {"序号", "姓名", "年龄"},
      {"1", "张三", strconv.Itoa(25)},
      {"2", "李四", strconv.Itoa(30)},
      {"3", "王五", strconv.Itoa(28)},
   }
   writer.WriteAll(data)

   writer.Flush()
   if err := writer.Error(); err != nil {
      log.Fatal(err)
   }
}