file.go 4.3 KB
Newer Older
xurime's avatar
xurime 已提交
1
// Copyright 2016 - 2020 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 7 8 9 10
// and read from XLSX / XLSM / XLTM files. Supports reading and writing
// spreadsheet documents generated by Microsoft Exce™ 2007 and later. Supports
// complex components by high compatibility, and provided streaming API for
// generating or reading data from a worksheet with huge amounts of data. This
// library needs Go version 1.10 or later.
xurime's avatar
xurime 已提交
11

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

import (
	"archive/zip"
	"bytes"
17
	"errors"
J
Josh Fyne 已提交
18 19
	"fmt"
	"io"
xurime's avatar
xurime 已提交
20 21 22
	"os"
)

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 30 31 32 33 34 35 36 37 38
	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)
39 40
	f := newFile()
	f.SheetCount, f.XLSX = 1, file
41 42
	f.CalcChain = f.calcChainReader()
	f.Comments = make(map[string]*xlsxComments)
43
	f.ContentTypes = f.contentTypesReader()
44
	f.Drawings = make(map[string]*xlsxWsDr)
45
	f.Styles = f.stylesReader()
46 47
	f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing)
	f.VMLDrawing = make(map[string]*vmlDrawing)
48
	f.WorkBook = f.workbookReader()
xurime's avatar
xurime 已提交
49 50
	f.Relationships = make(map[string]*xlsxRelationships)
	f.Relationships["xl/_rels/workbook.xml.rels"] = f.relsReader("xl/_rels/workbook.xml.rels")
xurime's avatar
xurime 已提交
51
	f.Sheet["xl/worksheets/sheet1.xml"], _ = f.workSheetReader("Sheet1")
52
	f.sheetMap["Sheet1"] = "xl/worksheets/sheet1.xml"
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 == "" {
xurime's avatar
xurime 已提交
60
		return fmt.Errorf("no path defined for file, consider File.WriteTo or File.Write")
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 70
		return errors.New("file name length exceeds maximum limit")
	}
J
Josh Fyne 已提交
71 72 73 74 75
	file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
	if err != nil {
		return err
	}
	defer file.Close()
76
	f.options = nil
xurime's avatar
xurime 已提交
77 78 79
	for _, o := range opt {
		f.options = &o
	}
J
Josh Fyne 已提交
80 81 82
	return f.Write(file)
}

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

// WriteTo implements io.WriterTo to write the file.
func (f *File) WriteTo(w io.Writer) (int64, error) {
91 92 93 94 95 96 97 98 99
	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 已提交
100
	buf := new(bytes.Buffer)
J
Josh Fyne 已提交
101
	zw := zip.NewWriter(buf)
102 103
	f.calcChainWriter()
	f.commentsWriter()
xurime's avatar
xurime 已提交
104
	f.contentTypesWriter()
105
	f.drawingsWriter()
106
	f.vmlDrawingWriter()
107 108
	f.workBookWriter()
	f.workSheetWriter()
xurime's avatar
xurime 已提交
109
	f.relsWriter()
xurime's avatar
xurime 已提交
110
	f.sharedStringsWriter()
111
	f.styleSheetWriter()
112

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

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

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