file.go 4.3 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 18
	"fmt"
	"io"
xurime's avatar
xurime 已提交
19 20 21
	"os"
)

xurime's avatar
xurime 已提交
22
// NewFile provides a function to create new file by default template. For
23 24
// example:
//
25
//    f := NewFile()
26
//
27
func NewFile() *File {
28 29 30 31 32 33 34 35 36 37
	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)
38 39
	f := newFile()
	f.SheetCount, f.XLSX = 1, file
40 41
	f.CalcChain = f.calcChainReader()
	f.Comments = make(map[string]*xlsxComments)
42
	f.ContentTypes = f.contentTypesReader()
43
	f.Drawings = make(map[string]*xlsxWsDr)
44
	f.Styles = f.stylesReader()
45 46
	f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing)
	f.VMLDrawing = make(map[string]*vmlDrawing)
47
	f.WorkBook = f.workbookReader()
xurime's avatar
xurime 已提交
48 49
	f.Relationships = make(map[string]*xlsxRelationships)
	f.Relationships["xl/_rels/workbook.xml.rels"] = f.relsReader("xl/_rels/workbook.xml.rels")
xurime's avatar
xurime 已提交
50
	f.Sheet["xl/worksheets/sheet1.xml"], _ = f.workSheetReader("Sheet1")
51
	f.sheetMap["Sheet1"] = "xl/worksheets/sheet1.xml"
xurime's avatar
xurime 已提交
52
	f.Theme = f.themeReader()
53
	return f
54 55
}

56
// Save provides a function to override the spreadsheet with origin path.
57
func (f *File) Save() error {
J
Josh Fyne 已提交
58
	if f.Path == "" {
xurime's avatar
xurime 已提交
59
		return fmt.Errorf("no path defined for file, consider File.WriteTo or File.Write")
60
	}
61
	return f.SaveAs(f.Path)
xurime's avatar
xurime 已提交
62 63
}

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

xurime's avatar
xurime 已提交
82
// Write provides a function to write to an io.Writer.
J
Josh Fyne 已提交
83
func (f *File) Write(w io.Writer) error {
84 85 86 87 88 89
	_, err := f.WriteTo(w)
	return err
}

// WriteTo implements io.WriterTo to write the file.
func (f *File) WriteTo(w io.Writer) (int64, error) {
90 91 92 93 94 95 96 97 98
	buf, err := f.WriteToBuffer()
	if err != nil {
		return 0, err
	}
	return buf.WriteTo(w)
}

// WriteToBuffer provides a function to get bytes.Buffer from the saved file.
func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
xurime's avatar
xurime 已提交
99
	buf := new(bytes.Buffer)
J
Josh Fyne 已提交
100
	zw := zip.NewWriter(buf)
101 102
	f.calcChainWriter()
	f.commentsWriter()
xurime's avatar
xurime 已提交
103
	f.contentTypesWriter()
104
	f.drawingsWriter()
105
	f.vmlDrawingWriter()
106 107
	f.workBookWriter()
	f.workSheetWriter()
xurime's avatar
xurime 已提交
108
	f.relsWriter()
xurime's avatar
xurime 已提交
109
	f.sharedStringsWriter()
110
	f.styleSheetWriter()
111

112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
	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()
	}

132
	for path, content := range f.XLSX {
133 134 135
		if _, ok := f.streams[path]; ok {
			continue
		}
J
Josh Fyne 已提交
136
		fi, err := zw.Create(path)
xurime's avatar
xurime 已提交
137
		if err != nil {
Z
zaddok 已提交
138
			zw.Close()
139
			return buf, err
xurime's avatar
xurime 已提交
140
		}
141
		_, err = fi.Write(content)
xurime's avatar
xurime 已提交
142
		if err != nil {
Z
zaddok 已提交
143
			zw.Close()
144
			return buf, err
xurime's avatar
xurime 已提交
145 146
		}
	}
xurime's avatar
xurime 已提交
147

148
	if f.options != nil && f.options.Password != "" {
xurime's avatar
xurime 已提交
149 150 151 152 153 154 155 156 157 158 159
		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
	}
160
	return buf, zw.Close()
xurime's avatar
xurime 已提交
161
}