There is a small demand in the recent project. You need to export the query results to excel. Java is relatively easy before, and poi can be easily implemented. After checking golang's document, we found that golang did not export an Excel package, however, there is an encoding/CSV package. After reading the package, you can find that the CSV file can be exported. We all know that the CSV file is actually an Excel file in text format. You can directly open or import the file in Excel.
It looks quite good and the problem can be solved as expected, but it turns out that it is better to test an immature language or library first. Xingchong unloaded the test example and successfully exported a text.csv file. Everything looks pretty good. However, after opening it, it's dumb: Chinese garbled characters. In fact, this problem is easy to understand. golang only supports UTF-8, the default Character Set of win Chinese version is gb2312 (GBK). In this case, direct transcoding is enough.
Due to the previous loss, this time we will directly report the file downcode and try: Save the text.csv file directly in ASCII format. After opening it, we will find that the carriage return character is lost, and all of them are changed to one line. This is depressing. Let's take a look at the source code first:
// 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}
As you can see, the code is very simple. Each line writes files in CSV format. It should be noted that there is a usercrlf in writer to specify whether to adapt to the carriage return line break. The default value is false. The problem should be solved here, but after usercrlf is set to true, the problem persists, it seems that there is a problem with transcoding.
Since the code is so simple, it is better to implement the Code directly and then output the transcoding. Here iconv-Go is used for transcoding and the implementation is as follows:
Package componentsimport ("bytes" "errors" iconv "github.com/djimenez/iconv-go")/***** Export Processing */const (out_encoding = "GBK" // output encoding) /*** export a CSV file and output byte array * the output encoding is specified through 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 ("") // Add the header for Index, Headelem: = range head {separate: = "," If Index = columnCount-1 {separate = "\ n"} datastr. writestring (headelem + separate)} // Add a data row for _, dataarray: = range data {if Len (dataarray )! = Columncount {// the number of data items is smaller than the number of columns err = errors. new ("exportcsv data format is error. ")} for index, dataelem: = range dataarray {separate: =", "If Index = columnCount-1 {separate =" \ n "} datastr. writestring (dataelem + separate)} // process the encoding out = make ([] Byte, Len (datastr. bytes () iconv. convert (datastr. bytes (), Out, "UTF-8", out_encoding) return}
Test it. The export is successful and there are no garbled characters.
Currently, this project can be used to export CSV files in simple format, but it cannot be used to export complex Excel files. I thought about the following methods:
- Using CGO and C for export is a consistent style for golang to handle similar problems. However, it is not very good to export excel, because C is very troublesome to export an excel in a complicated format.
- It doesn't matter how to call modules implemented by other languages. If you export a large volume of data, it is actually quite good. you can separate the time-and labor-consuming operations such as generating an Excel file.
- Directly generate the corresponding binary file according to the Excel file format, which may be difficult to implement, but it is true that once and for all, here is a link in the Excel format. If you are interested, you can implement it.