From 38ad20efc11c1872c4e62a12617f0300c138b867 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 7 May 2018 16:12:51 +0800 Subject: [PATCH] save bytes on memory instead of string --- chart.go | 4 ++-- comment.go | 4 ++-- excelize.go | 11 +++++++++-- file.go | 20 ++++++++++---------- lib.go | 19 +++++++++++-------- picture.go | 10 +++++----- rows.go | 14 +++++++------- shape.go | 2 +- sheet.go | 16 +++++++++++----- styles.go | 2 +- table.go | 2 +- templates.go | 4 ++++ 12 files changed, 64 insertions(+), 44 deletions(-) diff --git a/chart.go b/chart.go index 6168553..c71dd9f 100644 --- a/chart.go +++ b/chart.go @@ -549,7 +549,7 @@ func (f *File) addChart(formatSet *formatChart) { chart, _ := xml.Marshal(xlsxChartSpace) media := "xl/charts/chart" + strconv.Itoa(count+1) + ".xml" - f.saveFileList(media, string(chart)) + f.saveFileList(media, chart) } // drawBaseChart provides function to draw the c:plotArea element for bar, @@ -1151,5 +1151,5 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI } content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor) output, _ := xml.Marshal(content) - f.saveFileList(drawingXML, string(output)) + f.saveFileList(drawingXML, output) } diff --git a/comment.go b/comment.go index 6f2d624..41b4d6b 100644 --- a/comment.go +++ b/comment.go @@ -142,7 +142,7 @@ func (f *File) addDrawingVML(commentID int, drawingVML, cell string) { } vml.Shape = append(vml.Shape, shape) v, _ := xml.Marshal(vml) - f.XLSX[drawingVML] = string(v) + f.XLSX[drawingVML] = v } // addComment provides function to create chart as xl/comments%d.xml by given @@ -202,7 +202,7 @@ func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) { } comments.CommentList.Comment = append(comments.CommentList.Comment, cmt) v, _ := xml.Marshal(comments) - f.saveFileList(commentsXML, string(v)) + f.saveFileList(commentsXML, v) } // countComments provides function to get comments files count storage in the diff --git a/excelize.go b/excelize.go index 0b1e410..31fa370 100644 --- a/excelize.go +++ b/excelize.go @@ -23,7 +23,7 @@ type File struct { Styles *xlsxStyleSheet WorkBook *xlsxWorkbook WorkBookRels *xlsxWorkbookRels - XLSX map[string]string + XLSX map[string][]byte } // OpenFile take the name of an XLSX file and returns a populated XLSX file @@ -88,7 +88,7 @@ func (f *File) workSheetReader(sheet string) *xlsxWorksheet { } if f.Sheet[name] == nil { var xlsx xlsxWorksheet - xml.Unmarshal([]byte(f.readXML(name)), &xlsx) + xml.Unmarshal(f.readXML(name), &xlsx) if f.checked == nil { f.checked = make(map[string]bool) } @@ -141,6 +141,13 @@ func replaceWorkSheetsRelationshipsNameSpace(workbookMarshal string) string { return workbookMarshal } +func replaceWorkSheetsRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte { + var oldXmlns = []byte(``) + var newXmlns = []byte(``) + workbookMarshal = bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1) + return workbookMarshal +} + // UpdateLinkedValue fix linked values within a spreadsheet are not updating in // Office Excel 2007 and 2010. This function will be remove value tag when met a // cell have a linked value. Reference diff --git a/file.go b/file.go index 01e856d..36af6f8 100644 --- a/file.go +++ b/file.go @@ -14,16 +14,16 @@ import ( // xlsx := NewFile() // func NewFile() *File { - file := make(map[string]string) - file["_rels/.rels"] = XMLHeader + templateRels - file["docProps/app.xml"] = XMLHeader + templateDocpropsApp - file["docProps/core.xml"] = XMLHeader + templateDocpropsCore - file["xl/_rels/workbook.xml.rels"] = XMLHeader + templateWorkbookRels - file["xl/theme/theme1.xml"] = XMLHeader + templateTheme - file["xl/worksheets/sheet1.xml"] = XMLHeader + templateSheet - file["xl/styles.xml"] = XMLHeader + templateStyles - file["xl/workbook.xml"] = XMLHeader + templateWorkbook - file["[Content_Types].xml"] = XMLHeader + templateContentTypes + file := make(map[string][]byte) + file["_rels/.rels"] = []byte(XMLHeader + templateRels) + file["docProps/app.xml"] = []byte(XMLHeader + templateDocpropsApp) + file["docProps/core.xml"] = []byte(XMLHeader + templateDocpropsCore) + file["xl/_rels/workbook.xml.rels"] = []byte(XMLHeader + templateWorkbookRels) + file["xl/theme/theme1.xml"] = []byte(XMLHeader + templateTheme) + file["xl/worksheets/sheet1.xml"] = []byte(XMLHeader + templateSheet) + file["xl/styles.xml"] = []byte(XMLHeader + templateStyles) + file["xl/workbook.xml"] = []byte(XMLHeader + templateWorkbook) + file["[Content_Types].xml"] = []byte(XMLHeader + templateContentTypes) f := &File{ sheetMap: make(map[string]string), Sheet: make(map[string]*xlsxWorksheet), diff --git a/lib.go b/lib.go index c0426d6..a168781 100644 --- a/lib.go +++ b/lib.go @@ -12,8 +12,8 @@ import ( // ReadZipReader can be used to read an XLSX in memory without touching the // filesystem. -func ReadZipReader(r *zip.Reader) (map[string]string, int, error) { - fileList := make(map[string]string) +func ReadZipReader(r *zip.Reader) (map[string][]byte, int, error) { + fileList := make(map[string][]byte) worksheets := 0 for _, v := range r.File { fileList[v.Name] = readFile(v) @@ -27,21 +27,24 @@ func ReadZipReader(r *zip.Reader) (map[string]string, int, error) { } // readXML provides function to read XML content as string. -func (f *File) readXML(name string) string { +func (f *File) readXML(name string) []byte { if content, ok := f.XLSX[name]; ok { return content } - return "" + return []byte{} } // saveFileList provides function to update given file content in file list of // XLSX. -func (f *File) saveFileList(name, content string) { - f.XLSX[name] = XMLHeader + content +func (f *File) saveFileList(name string, content []byte) { + newContent := make([]byte, 0, len(XMLHeader)+len(content)) + newContent = append(newContent, []byte(XMLHeader)...) + newContent = append(newContent, content...) + f.XLSX[name] = newContent } // Read file content as string in a archive file. -func readFile(file *zip.File) string { +func readFile(file *zip.File) []byte { rc, err := file.Open() if err != nil { log.Fatal(err) @@ -49,7 +52,7 @@ func readFile(file *zip.File) string { buff := bytes.NewBuffer(nil) io.Copy(buff, rc) rc.Close() - return string(buff.Bytes()) + return buff.Bytes() } // ToAlphaString provides function to convert integer to Excel sheet column diff --git a/picture.go b/picture.go index a7f48d1..6c84cdd 100644 --- a/picture.go +++ b/picture.go @@ -142,7 +142,7 @@ func (f *File) addSheetRelationships(sheet, relType, target, targetMode string) TargetMode: targetMode, }) output, _ := xml.Marshal(sheetRels) - f.saveFileList(rels, string(output)) + f.saveFileList(rels, output) return rID } @@ -163,7 +163,7 @@ func (f *File) deleteSheetRelationships(sheet, rID string) { } } output, _ := xml.Marshal(sheetRels) - f.saveFileList(rels, string(output)) + f.saveFileList(rels, output) } // addSheetLegacyDrawing provides function to add legacy drawing element to @@ -257,7 +257,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he } content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor) output, _ := xml.Marshal(content) - f.saveFileList(drawingXML, string(output)) + f.saveFileList(drawingXML, output) } // addDrawingRelationships provides function to add image part relationships in @@ -285,7 +285,7 @@ func (f *File) addDrawingRelationships(index int, relType, target, targetMode st TargetMode: targetMode, }) output, _ := xml.Marshal(drawingRels) - f.saveFileList(rels, string(output)) + f.saveFileList(rels, output) return rID } @@ -307,7 +307,7 @@ func (f *File) addMedia(file, ext string) { count := f.countMedia() dat, _ := ioutil.ReadFile(file) media := "xl/media/image" + strconv.Itoa(count+1) + ext - f.XLSX[media] = string(dat) + f.XLSX[media] = dat } // setContentTypePartImageExtensions provides function to set the content type diff --git a/rows.go b/rows.go index 02a6876..ff1a8c3 100644 --- a/rows.go +++ b/rows.go @@ -29,9 +29,9 @@ func (f *File) GetRows(sheet string) [][]string { } if xlsx != nil { output, _ := xml.Marshal(f.Sheet[name]) - f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) + f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) } - decoder := xml.NewDecoder(strings.NewReader(f.readXML(name))) + decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name))) d := f.sharedStringsReader() var inElement string var r xlsxRow @@ -44,7 +44,7 @@ func (f *File) GetRows(sheet string) [][]string { } rows = append(rows, row) } - decoder = xml.NewDecoder(strings.NewReader(f.readXML(name))) + decoder = xml.NewDecoder(bytes.NewReader(f.readXML(name))) for { token, _ := decoder.Token() if token == nil { @@ -154,19 +154,19 @@ func (f *File) Rows(sheet string) (*Rows, error) { if err != nil { return nil, err } - f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) + f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) } return &Rows{ f: f, - decoder: xml.NewDecoder(strings.NewReader(f.readXML(name))), + decoder: xml.NewDecoder(bytes.NewReader(f.readXML(name))), }, nil } // getTotalRowsCols provides a function to get total columns and rows in a // worksheet. func (f *File) getTotalRowsCols(name string) (int, int) { - decoder := xml.NewDecoder(strings.NewReader(f.readXML(name))) + decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name))) var inElement string var r xlsxRow var tr, tc int @@ -244,7 +244,7 @@ func (f *File) sharedStringsReader() *xlsxSST { if f.SharedStrings == nil { var sharedStrings xlsxSST ss := f.readXML("xl/sharedStrings.xml") - if ss == "" { + if len(ss) == 0 { ss = f.readXML("xl/SharedStrings.xml") } xml.Unmarshal([]byte(ss), &sharedStrings) diff --git a/shape.go b/shape.go index f1328f7..0b93752 100644 --- a/shape.go +++ b/shape.go @@ -390,7 +390,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format } content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor) output, _ := xml.Marshal(content) - f.saveFileList(drawingXML, string(output)) + f.saveFileList(drawingXML, output) } // setShapeRef provides function to set color with hex model by given actual diff --git a/sheet.go b/sheet.go index f42226b..cb50d61 100644 --- a/sheet.go +++ b/sheet.go @@ -50,7 +50,7 @@ func (f *File) contentTypesReader() *xlsxTypes { func (f *File) contentTypesWriter() { if f.ContentTypes != nil { output, _ := xml.Marshal(f.ContentTypes) - f.saveFileList("[Content_Types].xml", string(output)) + f.saveFileList("[Content_Types].xml", output) } } @@ -70,7 +70,7 @@ func (f *File) workbookReader() *xlsxWorkbook { func (f *File) workbookWriter() { if f.WorkBook != nil { output, _ := xml.Marshal(f.WorkBook) - f.saveFileList("xl/workbook.xml", replaceRelationshipsNameSpace(string(output))) + f.saveFileList("xl/workbook.xml", replaceRelationshipsNameSpaceBytes(output)) } } @@ -83,7 +83,7 @@ func (f *File) worksheetWriter() { f.Sheet[path].SheetData.Row[k].C = trimCell(v.C) } output, _ := xml.Marshal(sheet) - f.saveFileList(path, replaceWorkSheetsRelationshipsNameSpace(string(output))) + f.saveFileList(path, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) ok := f.checked[path] if ok { f.checked[path] = false @@ -151,7 +151,7 @@ func (f *File) workbookRelsReader() *xlsxWorkbookRels { func (f *File) workbookRelsWriter() { if f.WorkBookRels != nil { output, _ := xml.Marshal(f.WorkBookRels) - f.saveFileList("xl/_rels/workbook.xml.rels", string(output)) + f.saveFileList("xl/_rels/workbook.xml.rels", output) } } @@ -183,7 +183,7 @@ func (f *File) addXlsxWorkbookRels(sheet int) int { // setAppXML update docProps/app.xml file of XML. func (f *File) setAppXML() { - f.saveFileList("docProps/app.xml", templateDocpropsApp) + f.saveFileList("docProps/app.xml", []byte(templateDocpropsApp)) } // Some tools that read XLSX files have very strict requirements about the @@ -199,6 +199,12 @@ func replaceRelationshipsNameSpace(workbookMarshal string) string { return strings.Replace(workbookMarshal, oldXmlns, newXmlns, -1) } +func replaceRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte { + oldXmlns := []byte(``) + newXmlns := []byte(``) + return bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1) +} + // SetActiveSheet provides function to set default active worksheet of XLSX by // given index. Note that active index is different with the index that got by // function GetSheetMap, and it should be greater than 0 and less than total diff --git a/styles.go b/styles.go index 6ebb603..0a9cbef 100644 --- a/styles.go +++ b/styles.go @@ -999,7 +999,7 @@ func (f *File) stylesReader() *xlsxStyleSheet { func (f *File) styleSheetWriter() { if f.Styles != nil { output, _ := xml.Marshal(f.Styles) - f.saveFileList("xl/styles.xml", replaceWorkSheetsRelationshipsNameSpace(string(output))) + f.saveFileList("xl/styles.xml", replaceWorkSheetsRelationshipsNameSpaceBytes(output)) } } diff --git a/table.go b/table.go index 5c00a2d..5af4b04 100644 --- a/table.go +++ b/table.go @@ -150,7 +150,7 @@ func (f *File) addTable(sheet, tableXML string, hxAxis, hyAxis, vxAxis, vyAxis, }, } table, _ := xml.Marshal(t) - f.saveFileList(tableXML, string(table)) + f.saveFileList(tableXML, table) } // parseAutoFilterSet provides function to parse the settings of the auto diff --git a/templates.go b/templates.go index b5f4f8c..d3f82ee 100644 --- a/templates.go +++ b/templates.go @@ -6,6 +6,10 @@ package excelize // XMLHeader define an XML declaration can also contain a standalone declaration. const XMLHeader = "\n" +var ( + XMLHeaderByte = []byte(XMLHeader) +) + const templateDocpropsApp = `0Golang Excelize` const templateContentTypes = ``