file.go 5.4 KB
Newer Older
1
// Copyright 2016 - 2021 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"
J
Josh Fyne 已提交
17
	"io"
xurime's avatar
xurime 已提交
18
	"os"
xurime's avatar
xurime 已提交
19
	"path/filepath"
20
	"sync"
xurime's avatar
xurime 已提交
21 22
)

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

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

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

84 85 86 87 88 89 90 91 92 93 94 95
// 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 已提交
96
// Write provides a function to write to an io.Writer.
J
Josh Fyne 已提交
97
func (f *File) Write(w io.Writer) error {
98 99 100 101 102 103
	_, err := f.WriteTo(w)
	return err
}

// WriteTo implements io.WriterTo to write the file.
func (f *File) WriteTo(w io.Writer) (int64, error) {
104 105 106 107 108 109 110 111
	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 {
112 113
		return 0, err
	}
114
	return 0, nil
115 116
}

xurime's avatar
xurime 已提交
117 118
// 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.
119
func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
xurime's avatar
xurime 已提交
120
	buf := new(bytes.Buffer)
J
Josh Fyne 已提交
121
	zw := zip.NewWriter(buf)
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

	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 已提交
146
		_ = zw.Close()
147 148 149 150 151 152 153
		return err
	}
	return zw.Close()
}

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

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