goalng導出excel(csv格式)

    最近項目中有個小需求,須要將查詢結果導出到excel。之間前java比較容易,使用POI很容易就能實現,查了下golang的文檔,發現golang下邊並無導出excel的包,可是卻有一個encoding/csv的包,看了下發現能夠導出csv文件,你們都知道csv文件其實就是文本格式的excel文件,能夠直接經過excel打開或是導入excel。

    看起來挺好的,問題如願解決,可是事實證實對已一個還不成熟的語言或是庫最好仍是先測一下的好。興沖沖的卸了測試例子,成功導出了一個text.csv文件,一切看起來都挺好的,然而打開以後就傻眼了:中文亂碼,這個問題其實比較好理解,golang只支持utf-8,而win中文版默認字符集是GB2312(gbk),這樣看來直接轉碼就好了唄。
    因爲以前吃了虧,此次咱們先直接報文件轉下碼試試:直接將以前導出的text.csv另存爲ASCII格式,打開後發現回車換行符丟了,所有變成一行了。這下就鬱悶了,先看下源碼吧:
html

// 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格式的連接,有興趣的能夠實現下。
相關文章
相關標籤/搜索