forked from p30928647/excelize
Optimize memory usage when stream flush and save (#659)
* use io.Copy from stream temp file to zip Writer * fix nil * log * build * delete log * fix compatibility for office * Update go module Co-authored-by: lijingfeng <lijingfeng@laiye.com> Co-authored-by: xuri <xuri.me@gmail.com>
This commit is contained in:
parent
f2b8798a34
commit
93160287bb
|
@ -36,6 +36,7 @@ type File struct {
|
||||||
xmlAttr map[string][]xml.Attr
|
xmlAttr map[string][]xml.Attr
|
||||||
checked map[string]bool
|
checked map[string]bool
|
||||||
sheetMap map[string]string
|
sheetMap map[string]string
|
||||||
|
streams map[string]*StreamWriter
|
||||||
CalcChain *xlsxCalcChain
|
CalcChain *xlsxCalcChain
|
||||||
Comments map[string]*xlsxComments
|
Comments map[string]*xlsxComments
|
||||||
ContentTypes *xlsxTypes
|
ContentTypes *xlsxTypes
|
||||||
|
|
20
file.go
20
file.go
|
@ -110,6 +110,26 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
|
||||||
f.sharedStringsWriter()
|
f.sharedStringsWriter()
|
||||||
f.styleSheetWriter()
|
f.styleSheetWriter()
|
||||||
|
|
||||||
|
for path, stream := range f.streams {
|
||||||
|
fi, err := zw.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
zw.Close()
|
||||||
|
return buf, err
|
||||||
|
}
|
||||||
|
var from io.Reader
|
||||||
|
from, err = stream.rawData.Reader()
|
||||||
|
if err != nil {
|
||||||
|
stream.rawData.Close()
|
||||||
|
return buf, err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(fi, from)
|
||||||
|
if err != nil {
|
||||||
|
zw.Close()
|
||||||
|
return buf, err
|
||||||
|
}
|
||||||
|
stream.rawData.Close()
|
||||||
|
}
|
||||||
|
|
||||||
for path, content := range f.XLSX {
|
for path, content := range f.XLSX {
|
||||||
fi, err := zw.Create(path)
|
fi, err := zw.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
||||||
module github.com/360EntSecGroup-Skylar/excelize/v2
|
module github.com/360EntSecGroup-Skylar/excelize/v2
|
||||||
|
|
||||||
go 1.15
|
go 1.11
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||||
|
|
44
stream.go
44
stream.go
|
@ -85,6 +85,13 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sheetXML := fmt.Sprintf("xl/worksheets/sheet%d.xml", sw.SheetID)
|
||||||
|
if f.streams == nil {
|
||||||
|
f.streams = make(map[string]*StreamWriter)
|
||||||
|
}
|
||||||
|
f.streams[sheetXML] = sw
|
||||||
|
|
||||||
sw.rawData.WriteString(XMLHeader + `<worksheet` + templateNamespaceIDMap)
|
sw.rawData.WriteString(XMLHeader + `<worksheet` + templateNamespaceIDMap)
|
||||||
bulkAppendFields(&sw.rawData, sw.worksheet, 2, 6)
|
bulkAppendFields(&sw.rawData, sw.worksheet, 2, 6)
|
||||||
sw.rawData.WriteString(`<sheetData>`)
|
sw.rawData.WriteString(`<sheetData>`)
|
||||||
|
@ -387,13 +394,8 @@ func (sw *StreamWriter) Flush() error {
|
||||||
sheetXML := fmt.Sprintf("xl/worksheets/sheet%d.xml", sw.SheetID)
|
sheetXML := fmt.Sprintf("xl/worksheets/sheet%d.xml", sw.SheetID)
|
||||||
delete(sw.File.Sheet, sheetXML)
|
delete(sw.File.Sheet, sheetXML)
|
||||||
delete(sw.File.checked, sheetXML)
|
delete(sw.File.checked, sheetXML)
|
||||||
|
delete(sw.File.XLSX, sheetXML)
|
||||||
|
|
||||||
defer sw.rawData.Close()
|
|
||||||
b, err := sw.rawData.Bytes()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sw.File.XLSX[sheetXML] = b
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,36 +446,6 @@ func (bw *bufferedWriter) Reader() (io.Reader, error) {
|
||||||
return io.NewSectionReader(bw.tmp, 0, fi.Size()), nil
|
return io.NewSectionReader(bw.tmp, 0, fi.Size()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bytes returns the entire content of the bufferedWriter. If a temp file is
|
|
||||||
// used, Bytes will efficiently allocate a buffer to prevent re-allocations.
|
|
||||||
func (bw *bufferedWriter) Bytes() ([]byte, error) {
|
|
||||||
if bw.tmp == nil {
|
|
||||||
return bw.buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := bw.Flush(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if fi, err := bw.tmp.Stat(); err == nil {
|
|
||||||
if size := fi.Size() + bytes.MinRead; size > bytes.MinRead {
|
|
||||||
if int64(int(size)) == size {
|
|
||||||
buf.Grow(int(size))
|
|
||||||
} else {
|
|
||||||
return nil, bytes.ErrTooLarge
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := bw.tmp.Seek(0, 0); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := buf.ReadFrom(bw.tmp)
|
|
||||||
return buf.Bytes(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync will write the in-memory buffer to a temp file, if the in-memory
|
// Sync will write the in-memory buffer to a temp file, if the in-memory
|
||||||
// buffer has grown large enough. Any error will be returned.
|
// buffer has grown large enough. Any error will be returned.
|
||||||
func (bw *bufferedWriter) Sync() (err error) {
|
func (bw *bufferedWriter) Sync() (err error) {
|
||||||
|
|
Loading…
Reference in New Issue