Performance improvement

This commit is contained in:
Ri Xu 2017-03-12 20:38:26 +08:00
parent 5384756d64
commit de6e075713
8 changed files with 75 additions and 185 deletions

54
cell.go
View File

@ -9,10 +9,8 @@ import (
// GetCellValue provides function to get value from cell by given sheet index
// and axis in XLSX file.
func (f *File) GetCellValue(sheet, axis string) string {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
@ -60,10 +58,8 @@ func (f *File) GetCellValue(sheet, axis string) string {
// GetCellFormula provides function to get formula from cell by given sheet
// index and axis in XLSX file.
func (f *File) GetCellFormula(sheet, axis string) string {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
@ -102,18 +98,8 @@ func (f *File) GetCellFormula(sheet, axis string) string {
// SetCellFormula provides function to set cell formula by given string and
// sheet index.
func (f *File) SetCellFormula(sheet, axis, formula string) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
@ -129,8 +115,8 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
rows := xAxis + 1
cell := yAxis + 1
completeRow(&xlsx, rows, cell)
completeCol(&xlsx, rows, cell)
completeRow(xlsx, rows, cell)
completeCol(xlsx, rows, cell)
if xlsx.SheetData.Row[xAxis].C[yAxis].F != nil {
xlsx.SheetData.Row[xAxis].C[yAxis].F.Content = formula
@ -140,25 +126,13 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
}
xlsx.SheetData.Row[xAxis].C[yAxis].F = &f
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// SetCellHyperLink provides function to set cell hyperlink by given sheet index
// and link URL address. Only support external link currently.
func (f *File) SetCellHyperLink(sheet, axis, link string) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
@ -178,8 +152,6 @@ func (f *File) SetCellHyperLink(sheet, axis, link string) {
hyperlinks.Hyperlink = append(hyperlinks.Hyperlink, hyperlink)
xlsx.Hyperlinks = &hyperlinks
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// MergeCell provides function to merge cells by given coordinate area and sheet
@ -218,17 +190,7 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
vyAxis, hyAxis = hyAxis, vyAxis
}
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
xlsx := f.workSheetReader(sheet)
if xlsx.MergeCells != nil {
mergeCell := xlsxMergeCell{}
// Correct the coordinate area, such correct C1:B3 to B1:C3.
@ -250,8 +212,6 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
mergeCells.Cells = append(mergeCells.Cells, &mergeCell)
xlsx.MergeCells = &mergeCells
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// checkCellInArea provides function to determine if a given coordinate is

15
col.go
View File

@ -1,7 +1,6 @@
package excelize
import (
"encoding/xml"
"math"
"strconv"
"strings"
@ -31,9 +30,7 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) {
if min > max {
min, max = max, min
}
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
col := xlsxCol{
Min: min,
Max: max,
@ -47,8 +44,6 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) {
cols.Col = append(cols.Col, col)
xlsx.Cols = &cols
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// positionObjectPixels calculate the vertices that define the position of a
@ -160,9 +155,7 @@ func (f *File) positionObjectPixels(sheet string, colStart, rowStart, x1, y1, wi
// getColWidth provides function to get column width in pixels by given sheet
// name and column index.
func (f *File) getColWidth(sheet string, col int) int {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
if xlsx.Cols != nil {
var width float64
for _, v := range xlsx.Cols.Col {
@ -181,9 +174,7 @@ func (f *File) getColWidth(sheet string, col int) int {
// getRowHeight provides function to get row height in pixels by given sheet
// name and row index.
func (f *File) getRowHeight(sheet string, row int) int {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
for _, v := range xlsx.SheetData.Row {
if v.R == row && v.Ht != "" {
ht, _ := strconv.ParseFloat(v.Ht, 64)

View File

@ -16,6 +16,7 @@ type File struct {
checked map[string]bool
XLSX map[string]string
Path string
Sheet map[string]*xlsxWorksheet
SheetCount int
}
@ -52,6 +53,7 @@ func OpenReader(r io.Reader) (*File, error) {
return nil, err
}
return &File{
Sheet: make(map[string]*xlsxWorksheet),
checked: make(map[string]bool),
XLSX: file,
Path: "",
@ -85,21 +87,32 @@ func (f *File) SetCellValue(sheet, axis string, value interface{}) {
}
}
// workSheetReader provides function to get the pointer to the structure after
// deserialization by given worksheet index.
func (f *File) workSheetReader(sheet string) *xlsxWorksheet {
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
worksheet := f.Sheet[name]
if worksheet == nil {
var xlsx xlsxWorksheet
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
f.Sheet[name] = &xlsx
worksheet = f.Sheet[name]
}
return worksheet
}
// SetCellInt provides function to set int type value of a cell.
func (f *File) SetCellInt(sheet, axis string, value int) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
@ -115,31 +128,18 @@ func (f *File) SetCellInt(sheet, axis string, value int) {
rows := xAxis + 1
cell := yAxis + 1
completeRow(&xlsx, rows, cell)
completeCol(&xlsx, rows, cell)
completeRow(xlsx, rows, cell)
completeCol(xlsx, rows, cell)
xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
xlsx.SheetData.Row[xAxis].C[yAxis].V = strconv.Itoa(value)
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// SetCellStr provides function to set string type value of a cell. Total number
// of characters that a cell can contain 32767 characters.
func (f *File) SetCellStr(sheet, axis, value string) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
@ -158,31 +158,18 @@ func (f *File) SetCellStr(sheet, axis, value string) {
rows := xAxis + 1
cell := yAxis + 1
completeRow(&xlsx, rows, cell)
completeCol(&xlsx, rows, cell)
completeRow(xlsx, rows, cell)
completeCol(xlsx, rows, cell)
xlsx.SheetData.Row[xAxis].C[yAxis].T = "str"
xlsx.SheetData.Row[xAxis].C[yAxis].V = value
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// SetCellDefault provides function to set string type value of a cell as
// default format without escaping the cell.
func (f *File) SetCellDefault(sheet, axis, value string) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
@ -198,14 +185,11 @@ func (f *File) SetCellDefault(sheet, axis, value string) {
rows := xAxis + 1
cell := yAxis + 1
completeRow(&xlsx, rows, cell)
completeCol(&xlsx, rows, cell)
completeRow(xlsx, rows, cell)
completeCol(xlsx, rows, cell)
xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
xlsx.SheetData.Row[xAxis].C[yAxis].V = value
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// Completion column element tags of XML in a sheet.
@ -364,9 +348,7 @@ func checkRow(xlsx *xlsxWorksheet) {
//
func (f *File) UpdateLinkedValue() {
for i := 1; i <= f.SheetCount; i++ {
var xlsx xlsxWorksheet
name := "xl/worksheets/sheet" + strconv.Itoa(i) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader("sheet" + strconv.Itoa(i))
for indexR, row := range xlsx.SheetData.Row {
for indexC, col := range row.C {
if col.F != nil && col.V != "" {
@ -375,7 +357,5 @@ func (f *File) UpdateLinkedValue() {
}
}
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
}

14
file.go
View File

@ -3,6 +3,7 @@ package excelize
import (
"archive/zip"
"bytes"
"encoding/xml"
"fmt"
"io"
"os"
@ -25,7 +26,8 @@ func CreateFile() *File {
file["xl/workbook.xml"] = templateWorkbook
file["[Content_Types].xml"] = templateContentTypes
return &File{
XLSX: file,
XLSX: file,
Sheet: make(map[string]*xlsxWorksheet),
}
}
@ -52,6 +54,16 @@ func (f *File) WriteTo(name string) error {
func (f *File) Write(w io.Writer) error {
buf := new(bytes.Buffer)
zw := zip.NewWriter(buf)
for path, sheet := range f.Sheet {
if sheet == nil {
continue
}
output, err := xml.Marshal(sheet)
if err != nil {
return err
}
f.saveFileList(path, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
for path, content := range f.XLSX {
fi, err := zw.Create(path)
if err != nil {

View File

@ -87,9 +87,7 @@ func (f *File) AddPicture(sheet, cell, picture, format string) error {
_, file := filepath.Split(picture)
formatSet := parseFormatPictureSet(format)
// Read sheet data.
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
// Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder.
drawingID := f.countDrawings() + 1
pictureID := f.countMedia() + 1
@ -149,33 +147,19 @@ func (f *File) addSheetRelationships(sheet, relType, target, targetMode string)
// addSheetDrawing provides function to add drawing element to
// xl/worksheets/sheet%d.xml by given sheet name and relationship index.
func (f *File) addSheetDrawing(sheet string, rID int) {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
xlsx.Drawing = &xlsxDrawing{
RID: "rId" + strconv.Itoa(rID),
}
output, err := xml.Marshal(xlsx)
if err != nil {
fmt.Println(err)
}
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// addSheetPicture provides function to add picture element to
// xl/worksheets/sheet%d.xml by given sheet name and relationship index.
func (f *File) addSheetPicture(sheet string, rID int) {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
xlsx.Picture = &xlsxPicture{
RID: "rId" + strconv.Itoa(rID),
}
output, err := xml.Marshal(xlsx)
if err != nil {
fmt.Println(err)
}
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// countDrawings provides function to get drawing files count storage in the

22
rows.go
View File

@ -17,13 +17,15 @@ import (
// }
//
func (f *File) GetRows(sheet string) [][]string {
xlsx := f.workSheetReader(sheet)
rows := [][]string{}
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
decoder := xml.NewDecoder(strings.NewReader(f.readXML(name)))
d, err := readXMLSST(f)
if err != nil {
return rows
if xlsx != nil {
output, _ := xml.Marshal(f.Sheet[name])
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
decoder := xml.NewDecoder(strings.NewReader(f.readXML(name)))
d, _ := readXMLSST(f)
var inElement string
var r xlsxRow
var row []string
@ -105,20 +107,12 @@ func (f *File) getTotalRowsCols(sheet string) (int, int) {
// }
//
func (f *File) SetRowHeight(sheet string, rowIndex int, height float64) {
xlsx := xlsxWorksheet{}
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
rows := rowIndex + 1
cells := 0
completeRow(&xlsx, rows, cells)
completeRow(xlsx, rows, cells)
xlsx.SheetData.Row[rowIndex].Ht = strconv.FormatFloat(height, 'f', -1, 64)
xlsx.SheetData.Row[rowIndex].CustomHeight = true
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
// readXMLSST read xmlSST simple function.

View File

@ -22,9 +22,9 @@ func (f *File) NewSheet(index int, name string) {
// Create new sheet /xl/worksheets/sheet%d.xml
f.setSheet(index)
// Update xl/_rels/workbook.xml.rels
rid := f.addXlsxWorkbookRels(index)
rID := f.addXlsxWorkbookRels(index)
// Update xl/workbook.xml
f.setWorkbook(name, rid)
f.setWorkbook(name, rID)
}
// Read and update property of contents type of XLSX.
@ -49,12 +49,8 @@ func (f *File) setSheet(index int) {
xlsx.SheetViews.SheetView = append(xlsx.SheetViews.SheetView, xlsxSheetView{
WorkbookViewID: 0,
})
output, err := xml.Marshal(xlsx)
if err != nil {
fmt.Println(err)
}
path := "xl/worksheets/sheet" + strconv.Itoa(index) + ".xml"
f.saveFileList(path, replaceWorkSheetsRelationshipsNameSpace(string(output)))
f.Sheet[path] = &xlsx
}
// setWorkbook update workbook property of XLSX. Maximum 31 characters are
@ -151,14 +147,9 @@ func (f *File) SetActiveSheet(index int) {
}
f.saveFileList("xl/workbook.xml", replaceRelationshipsNameSpace(string(output)))
index++
buffer := bytes.Buffer{}
for i := 0; i < sheets; i++ {
xlsx := xlsxWorksheet{}
sheetIndex := i + 1
buffer.WriteString("xl/worksheets/sheet")
buffer.WriteString(strconv.Itoa(sheetIndex))
buffer.WriteString(".xml")
xml.Unmarshal([]byte(f.readXML(buffer.String())), &xlsx)
xlsx := f.workSheetReader("sheet" + strconv.Itoa(sheetIndex))
if index == sheetIndex {
if len(xlsx.SheetViews.SheetView) > 0 {
xlsx.SheetViews.SheetView[0].TabSelected = true
@ -172,12 +163,6 @@ func (f *File) SetActiveSheet(index int) {
xlsx.SheetViews.SheetView[0].TabSelected = false
}
}
sheet, err := xml.Marshal(xlsx)
if err != nil {
fmt.Println(err)
}
f.saveFileList(buffer.String(), replaceWorkSheetsRelationshipsNameSpace(string(sheet)))
buffer.Reset()
}
return
}
@ -275,10 +260,6 @@ func (f *File) SetSheetBackground(sheet, picture string) error {
if !ok {
return errors.New("Unsupported image extension")
}
// Read sheet data.
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
pictureID := f.countMedia() + 1
rID := f.addSheetRelationships(sheet, SourceRelationshipImage, "../media/image"+strconv.Itoa(pictureID)+ext, "")
f.addSheetPicture(sheet, rID)

View File

@ -196,20 +196,10 @@ func (f *File) setCellStyle(sheet, hcell, vcell string, styleID int) {
hcell = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1)
vcell = toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
xlsx := f.workSheetReader(sheet)
completeRow(&xlsx, vxAxis+1, vyAxis+1)
completeCol(&xlsx, vxAxis+1, vyAxis+1)
completeRow(xlsx, vxAxis+1, vyAxis+1)
completeCol(xlsx, vxAxis+1, vyAxis+1)
for r, row := range xlsx.SheetData.Row {
for k, c := range row.C {
@ -218,6 +208,4 @@ func (f *File) setCellStyle(sheet, hcell, vcell string, styleID int) {
}
}
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}