file.go 5.6 KB
Newer Older
1
// Copyright 2016 - 2022 The excelize Authors. All rights reserved. Use of
xurime's avatar
xurime 已提交
2 3 4 5
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
// Package excelize providing a set of functions that allow you to write to
xurime's avatar
xurime 已提交
6
// and read from XLSX / XLSM / XLTM files. Supports reading and writing
xurime's avatar
xurime 已提交
7
// spreadsheet documents generated by Microsoft Excel™ 2007 and later. Supports
xurime's avatar
xurime 已提交
8 9
// complex components by high compatibility, and provided streaming API for
// generating or reading data from a worksheet with huge amounts of data. This
10
// library needs Go version 1.15 or later.
xurime's avatar
xurime 已提交
11

xurime's avatar
xurime 已提交
12 13 14 15 16
package excelize

import (
	"archive/zip"
	"bytes"
17
	"encoding/xml"
J
Josh Fyne 已提交
18
	"io"
xurime's avatar
xurime 已提交
19
	"os"
xurime's avatar
xurime 已提交
20
	"path/filepath"
21
	"sync"
xurime's avatar
xurime 已提交
22 23
)

xurime's avatar
xurime 已提交
24
// NewFile provides a function to create new file by default template. For
25 26
// example:
//
27
//    f := NewFile()
28
//
29
func NewFile() *File {
30
	f := newFile()
31
	f.Pkg.Store("_rels/.rels", []byte(xml.Header+templateRels))
32 33
	f.Pkg.Store(defaultXMLPathDocPropsApp, []byte(xml.Header+templateDocpropsApp))
	f.Pkg.Store(defaultXMLPathDocPropsCore, []byte(xml.Header+templateDocpropsCore))
34 35 36 37 38 39
	f.Pkg.Store("xl/_rels/workbook.xml.rels", []byte(xml.Header+templateWorkbookRels))
	f.Pkg.Store("xl/theme/theme1.xml", []byte(xml.Header+templateTheme))
	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(xml.Header+templateSheet))
	f.Pkg.Store(defaultXMLPathStyles, []byte(xml.Header+templateStyles))
	f.Pkg.Store(defaultXMLPathWorkbook, []byte(xml.Header+templateWorkbook))
	f.Pkg.Store(defaultXMLPathContentTypes, []byte(xml.Header+templateContentTypes))
40
	f.SheetCount = 1
41 42
	f.CalcChain = f.calcChainReader()
	f.Comments = make(map[string]*xlsxComments)
43
	f.ContentTypes = f.contentTypesReader()
44
	f.Drawings = sync.Map{}
45
	f.Styles = f.stylesReader()
46 47
	f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing)
	f.VMLDrawing = make(map[string]*vmlDrawing)
48
	f.WorkBook = f.workbookReader()
49 50
	f.Relationships = sync.Map{}
	f.Relationships.Store("xl/_rels/workbook.xml.rels", f.relsReader("xl/_rels/workbook.xml.rels"))
51
	f.sheetMap["Sheet1"] = "xl/worksheets/sheet1.xml"
52 53
	ws, _ := f.workSheetReader("Sheet1")
	f.Sheet.Store("xl/worksheets/sheet1.xml", ws)
xurime's avatar
xurime 已提交
54
	f.Theme = f.themeReader()
55
	return f
56 57
}

58
// Save provides a function to override the spreadsheet with origin path.
59
func (f *File) Save() error {
J
Josh Fyne 已提交
60
	if f.Path == "" {
61
		return ErrSave
62
	}
63
	return f.SaveAs(f.Path)
xurime's avatar
xurime 已提交
64 65
}

66
// SaveAs provides a function to create or update to an spreadsheet at the
xurime's avatar
xurime 已提交
67
// provided path.
xurime's avatar
xurime 已提交
68
func (f *File) SaveAs(name string, opt ...Options) error {
69
	if len(name) > MaxFileNameLength {
70
		return ErrMaxFileNameLength
71
	}
72
	f.Path = name
xurime's avatar
xurime 已提交
73
	file, err := os.OpenFile(filepath.Clean(name), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
J
Josh Fyne 已提交
74 75 76 77
	if err != nil {
		return err
	}
	defer file.Close()
78
	f.options = nil
xurime's avatar
xurime 已提交
79 80
	for i := range opt {
		f.options = &opt[i]
xurime's avatar
xurime 已提交
81
	}
J
Josh Fyne 已提交
82 83 84
	return f.Write(file)
}

85 86 87 88 89 90 91 92 93 94 95 96
// Close closes and cleanup the open temporary file for the spreadsheet.
func (f *File) Close() error {
	var err error
	f.tempFiles.Range(func(k, v interface{}) bool {
		if err = os.Remove(v.(string)); err != nil {
			return false
		}
		return true
	})
	return err
}

xurime's avatar
xurime 已提交
97
// Write provides a function to write to an io.Writer.
J
Josh Fyne 已提交
98
func (f *File) Write(w io.Writer) error {
99 100 101 102 103 104
	_, err := f.WriteTo(w)
	return err
}

// WriteTo implements io.WriterTo to write the file.
func (f *File) WriteTo(w io.Writer) (int64, error) {
105 106 107 108 109 110 111 112
	if f.options != nil && f.options.Password != "" {
		buf, err := f.WriteToBuffer()
		if err != nil {
			return 0, err
		}
		return buf.WriteTo(w)
	}
	if err := f.writeDirectToWriter(w); err != nil {
113 114
		return 0, err
	}
115
	return 0, nil
116 117
}

xurime's avatar
xurime 已提交
118 119
// WriteToBuffer provides a function to get bytes.Buffer from the saved file,
// and it allocates space in memory. Be careful when the file size is large.
120
func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
xurime's avatar
xurime 已提交
121
	buf := new(bytes.Buffer)
J
Josh Fyne 已提交
122
	zw := zip.NewWriter(buf)
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

	if err := f.writeToZip(zw); err != nil {
		return buf, zw.Close()
	}

	if f.options != nil && f.options.Password != "" {
		if err := zw.Close(); err != nil {
			return buf, err
		}
		b, err := Encrypt(buf.Bytes(), f.options)
		if err != nil {
			return buf, err
		}
		buf.Reset()
		buf.Write(b)
		return buf, nil
	}
	return buf, zw.Close()
}

// writeDirectToWriter provides a function to write to io.Writer.
func (f *File) writeDirectToWriter(w io.Writer) error {
	zw := zip.NewWriter(w)
	if err := f.writeToZip(zw); err != nil {
xurime's avatar
xurime 已提交
147
		_ = zw.Close()
148 149 150 151 152 153 154
		return err
	}
	return zw.Close()
}

// writeToZip provides a function to write to zip.Writer
func (f *File) writeToZip(zw *zip.Writer) error {
155 156
	f.calcChainWriter()
	f.commentsWriter()
xurime's avatar
xurime 已提交
157
	f.contentTypesWriter()
158
	f.drawingsWriter()
159
	f.vmlDrawingWriter()
160 161
	f.workBookWriter()
	f.workSheetWriter()
xurime's avatar
xurime 已提交
162
	f.relsWriter()
163
	f.sharedStringsLoader()
xurime's avatar
xurime 已提交
164
	f.sharedStringsWriter()
165
	f.styleSheetWriter()
166

167 168 169
	for path, stream := range f.streams {
		fi, err := zw.Create(path)
		if err != nil {
170
			return err
171 172 173 174
		}
		var from io.Reader
		from, err = stream.rawData.Reader()
		if err != nil {
xurime's avatar
xurime 已提交
175
			_ = stream.rawData.Close()
176
			return err
177 178 179
		}
		_, err = io.Copy(fi, from)
		if err != nil {
180
			return err
181
		}
xurime's avatar
xurime 已提交
182
		_ = stream.rawData.Close()
183
	}
184 185
	var err error
	f.Pkg.Range(func(path, content interface{}) bool {
xurime's avatar
xurime 已提交
186
		if err != nil {
187
			return false
xurime's avatar
xurime 已提交
188
		}
189 190 191 192 193
		if _, ok := f.streams[path.(string)]; ok {
			return true
		}
		var fi io.Writer
		fi, err = zw.Create(path.(string))
xurime's avatar
xurime 已提交
194
		if err != nil {
195
			return false
xurime's avatar
xurime 已提交
196
		}
197 198 199
		_, err = fi.Write(content.([]byte))
		return true
	})
200
	f.tempFiles.Range(func(path, content interface{}) bool {
201 202 203
		if _, ok := f.Pkg.Load(path); ok {
			return true
		}
204 205 206 207 208 209 210 211
		var fi io.Writer
		fi, err = zw.Create(path.(string))
		if err != nil {
			return false
		}
		_, err = fi.Write(f.readBytes(path.(string)))
		return true
	})
212
	return err
xurime's avatar
xurime 已提交
213
}