file.go 3.9 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
//    xlsx := 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
}

xurime's avatar
xurime 已提交
57
// Save provides a function to override the xlsx file 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
}

xurime's avatar
xurime 已提交
65 66
// SaveAs provides a function to create or update to an xlsx file at the
// provided path.
xurime's avatar
xurime 已提交
67
func (f *File) SaveAs(name string, opt ...Options) error {
68 69 70
	if len(name) > FileNameLength {
		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()
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
	for path, content := range f.XLSX {
J
Josh Fyne 已提交
113
		fi, err := zw.Create(path)
xurime's avatar
xurime 已提交
114
		if err != nil {
Z
zaddok 已提交
115
			zw.Close()
116
			return buf, err
xurime's avatar
xurime 已提交
117
		}
118
		_, err = fi.Write(content)
xurime's avatar
xurime 已提交
119
		if err != nil {
Z
zaddok 已提交
120
			zw.Close()
121
			return buf, err
xurime's avatar
xurime 已提交
122 123
		}
	}
xurime's avatar
xurime 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136

	if f.options != nil {
		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
	}
137
	return buf, zw.Close()
xurime's avatar
xurime 已提交
138
}