最近项目中有个小需求,需要将查询结果导出到excel。之间前java比较容易,使用POI很容易就能实现,查了下golang的文档,发现golang下边并没有导出excel的包,但是却有一个encoding/csv的包,看了下发现可以导出csv文件,大家都知道csv文件其实就是文本格式的excel文件,可以直接通过excel打开或是导入excel。

看起来挺好的,问题如愿解决,但是事实证明对已一个还不成熟的语言或是库最好还是先测一下的好。兴冲冲的卸了测试例子,成功导出了一个text.csv文件,一切看起来都挺好的,然而打开之后就傻眼了:中文乱码,这个问题其实比较好理解,golang只支持utf-8,而win中文版默认字符集是GB2312(gbk),这样看来直接转码就行了呗。
    由于之前吃了亏,这次我们先直接报文件转下码试试:直接将之前导出的text.csv另存为ASCII格式,打开后发现回车换行符丢了,全部变成一行了。这下就郁闷了,先看下源码吧:

// Writer writes a single CSV record to w along with any necessary quoting.
// A record is a slice of strings with each string being one field.
func (w *Writer) Write(record []string) (err error) {
for n, field := range record {
if n > 0 {
if _, err = w.w.WriteRune(w.Comma); err != nil {
return
}
} // If we don't have to have a quoted field then just
// write out the field and continue to the next field.
if !w.fieldNeedsQuotes(field) {
if _, err = w.w.WriteString(field); err != nil {
return
}
continue
}
if err = w.w.WriteByte('"'); err != nil {
return
} for _, r1 := range field {
switch r1 {
case '"':
_, err = w.w.WriteString(`""`)
case '\r':
if !w.UseCRLF {
err = w.w.WriteByte('\r')
}
case '\n':
if w.UseCRLF {
_, err = w.w.WriteString("\r\n")
} else {
err = w.w.WriteByte('\n')
}
default:
_, err = w.w.WriteRune(r1)
}
if err != nil {
return
}
} if err = w.w.WriteByte('"'); err != nil {
return
}
}
if w.UseCRLF {
_, err = w.w.WriteString("\r\n")
} else {
err = w.w.WriteByte('\n')
}
return
}

可以看到代码十分简单,每行就是按照csv的格式写入文件而已。需要注意的是writer里边有一个UserCRLF来指定是否适应回车换行符,默认为false,问题应该就出在这里,但是将UserCRLF设置为true之后,问题依旧,看来是转码有问题。
    既然代码这么简单,那么还不如直接自己实现,然后转码输出,这里使用iconv-go进行转码,实现如下:

package components

import (
"bytes"
"errors"
iconv "github.com/djimenez/iconv-go"
) /**
* 导出处理
*/ const (
OUT_ENCODING = "gbk" //输出编码
) /**
* 导出csv格式文件,输出byte数组
* 输出编码通过OUT_ENCODING指定
*/
func ExportCsv(head []string, data [][]string) (out []byte, err error) {
if len(head) == 0 {
err = errors.New("ExportCsv Head is nil")
return
} columnCount := len(head)
dataStr := bytes.NewBufferString("")
//添加头
for index, headElem := range head {
separate := ","
if index == columnCount-1 {
separate = "\n"
}
dataStr.WriteString(headElem + separate)
} //添加数据行
for _, dataArray := range data {
if len(dataArray) != columnCount { //数据项数小于列数
err = errors.New("ExportCsv data format is error.")
}
for index, dataElem := range dataArray {
separate := ","
if index == columnCount-1 {
separate = "\n"
}
dataStr.WriteString(dataElem + separate)
}
} //处理编码
out = make([]byte, len(dataStr.Bytes()))
iconv.Convert(dataStr.Bytes(), out, "utf-8", OUT_ENCODING)
return
}

测试一下,导出成功,而且没有乱码问题。
    对于目前这个项目而言,导出简单格式的csv就能满足,但是如果想导出复杂的excel文件就不行了。考虑了下大概想出了以下几种方法:

  • 使用cgo,用c来实现导出,这是golang处理类似问题的一贯作风,然而就导出excel而言并不太好,因为c导出复杂格式的excel本身就挺麻烦的
  • 调用其他语言实现的模块,至于怎么调就无所谓,如果对于大批量的导出,其实还挺好的,可以把生成excel这样费时费力的操作给分离出去
  • 按照excel文件格式直接生成为对应二进制文件,这个实现起来可能比较费劲,但是确实一劳永逸的,这里附一个excel格式的链接,有兴趣的可以实现下。

goalng导出excel(csv格式)的更多相关文章

  1. (转载)DBGridEh导出Excel等格式文件

    DBGridEh导出Excel等格式文件 uses DBGridEhImpExp; {--------------------------------------------------------- ...

  2. PHP 高效导入导出Excel(csv)方法之fgetcsv()和fputcsv()函数

    CSV,是Comma Separated Value(逗号分隔值)的英文缩写,通常都是纯文本文件. 一.CSV数据导入函数fgetcsv() fgetcsv() 函数从文件指针中读入一行并解析 CSV ...

  3. Elasticsearch:如何把Elasticsearch中的数据导出为CSV格式的文件

    本教程向您展示如何将数据从Elasticsearch导出到CSV文件. 想象一下,您想要在Excel中打开一些Elasticsearch中的数据,并根据这些数据创建数据透视表. 这只是一个用例,其中将 ...

  4. AX导出excel设置格式

    今天在AX2009里面写一个导出EXCEL,没有模版,这是第一次碰到,之后写完之后发现导出的数据格式不对. 到处取经之后得到一下结果: 定义一个 Com   range; SysExcelCells  ...

  5. POI导入导出Excel(HSSF格式,User Model方式)

    1.POI说明 Apache POI是Apache软件基金会的开源代码库, POI提供对Microsoft Office格式档案读和写的功能. POI支持的格式: HSSF - 提供读写Microso ...

  6. 将数据 导出excel表格式

    我的考试完提交生成的数据 这是我的考试题类型 //导出调查评议的数据 public function diaocha(){ $xlsName = '表格形式 调查评议 信息'; $xlsTitle = ...

  7. Asp.net导出Excel/Csv文本格式数据

    刚刚开始做Excel相关的项目,所以遇到的问题不管大小都给记录一下 偶然的机会在添加数据的时候全改成了数字,结果输出的时候全自动变成了科学计数法,这是excel的强大功能,能自动识别数字和字符串,太聪 ...

  8. mongodb导出数据csv格式

    mongoexport -d test -c item --type=csv -f salary,city,workYear,companyShortName -o user.csvmongoexpo ...

  9. c# 导入导出excel表格式

    c#使用代码导入excel时,当遇到纯数字且大于15位时会出现编码混乱(表现为科学计数法),要想呈现与excel表中纯数字格式和在数据库中呈现纯数字,操作如下: 完成即可. 导出取决于导入的内容排版.

随机推荐

  1. Error: Can't set headers after they are sent.

    Error: Can't set headers after they are sent. 错误:无法设置头信息后发送. 具体报错: 看到了一下代码,自己写错了 没有进行错误判断,两个条件都直接返回, ...

  2. spring boot Filter过滤器的简单使用

    springboot使用Filter过滤器有两种方式: 一种是实现Filter接口然后通过@Component注解向项目加入过滤器 另一种是通过配置类来配置过滤器 @Component public ...

  3. ThreadLocal源码解析,内存泄露以及传递性

    我想ThreadLocal这东西,大家或多或少都了解过一点,我在接触ThreadLocal的时候,觉得这东西很神奇,在网上看了很多博客,也看了一些书,总觉得有一个坎跨不过去,所以对ThreadLoca ...

  4. js push(),pop(),shift(),unshift()

    以前没有太在意这些,这几天看<Javascript 设计模式与开发实践>(不得不说这是一本好书) 发现总是会用到这几个函数,可是有什么区别呢?? 简单来说是两套东西(数据结构时老师详细的讲 ...

  5. GreenDao 3.x 注解中ToOne和ToMany的个人理解

    GreenDao是什么东西这个就不用多说了.自从GreenDao升级到3.0之后,编译的方法发生了改变.当然这个改变是有助于快速开发的. 区别在哪随便百度一下都可以知道.这里就不多说了. 这里主要说的 ...

  6. freebsd新添加磁盘

    1.添加硬盘 2.查看现在的硬盘 3.执行sysinstall命令 4. 5. 6.按下enter键 7.A,C,Q 8. 9. 10.C,Q 11.newfs /dev/ad0 12.cd / &a ...

  7. WebClient UI和Tomcat的启动器

    WebClient UI 我们在WebClient UI的开发工具里点了Test按钮, 会在浏览器以测试模式打开选中的view.这背后发生了什么事?注意浏览器地址栏的bspwd_cmp_test,这是 ...

  8. Predicate和Consumer接口的使用

    //  Predicate   判断是否拥有资格,Consumer  改变输入的值 案例 public static MyTest2 getV(MyTest2 a, Predicate<MyTe ...

  9. 百度site网址显示完整站点信息的分析

    去年赛花红就发现百度site本博客网址,仅出现找到相关结果数约多少个,数字为估算值,网站管理员如需了解更准确的索引量,请使用百度站长平台等字样.但赛花红又发现有的网站却显示着完整的站点信息,当时以为是 ...

  10. NHibernate使用之详细图解

    本文档适合初级开发者或者是第一次接触NHibernate框架的朋友,其中NHibernate不是最新的版本,但是一个比较经典的版本 NHibernate 2.1.2,其中用红线标注的部分一定要仔细看, ...