save bytes on memory instead of string

This commit is contained in:
Lunny Xiao 2018-05-07 16:12:51 +08:00
parent bc451a78de
commit 38ad20efc1
No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
12 changed files with 64 additions and 44 deletions

View File

@ -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)
}

View File

@ -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

View File

@ -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(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
var newXmlns = []byte(`<worksheet xr:uid="{00000000-0001-0000-0000-000000000000}" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" mc:Ignorable="x14ac xr xr2 xr3" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mx="http://schemas.microsoft.com/office/mac/excel/2008/main" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
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

20
file.go
View File

@ -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),

19
lib.go
View File

@ -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

View File

@ -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

14
rows.go
View File

@ -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)

View File

@ -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

View File

@ -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(`<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
newXmlns := []byte(`<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x15" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main">`)
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

View File

@ -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))
}
}

View File

@ -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

View File

@ -6,6 +6,10 @@ package excelize
// XMLHeader define an XML declaration can also contain a standalone declaration.
const XMLHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
var (
XMLHeaderByte = []byte(XMLHeader)
)
const templateDocpropsApp = `<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><TotalTime>0</TotalTime><Application>Golang Excelize</Application></Properties>`
const templateContentTypes = `<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/></Types>`