file.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
  2. // this source code is governed by a BSD-style license that can be found in
  3. // the LICENSE file.
  4. //
  5. // Package excelize providing a set of functions that allow you to write to
  6. // and read from XLSX / XLSM / XLTM files. Supports reading and writing
  7. // spreadsheet documents generated by Microsoft Excel™ 2007 and later. Supports
  8. // complex components by high compatibility, and provided streaming API for
  9. // generating or reading data from a worksheet with huge amounts of data. This
  10. // library needs Go version 1.15 or later.
  11. package excelize
  12. import (
  13. "archive/zip"
  14. "bytes"
  15. "fmt"
  16. "io"
  17. "os"
  18. "sync"
  19. )
  20. // NewFile provides a function to create new file by default template. For
  21. // example:
  22. //
  23. // f := NewFile()
  24. //
  25. func NewFile() *File {
  26. f := newFile()
  27. f.Pkg.Store("_rels/.rels", []byte(XMLHeader+templateRels))
  28. f.Pkg.Store("docProps/app.xml", []byte(XMLHeader+templateDocpropsApp))
  29. f.Pkg.Store("docProps/core.xml", []byte(XMLHeader+templateDocpropsCore))
  30. f.Pkg.Store("xl/_rels/workbook.xml.rels", []byte(XMLHeader+templateWorkbookRels))
  31. f.Pkg.Store("xl/theme/theme1.xml", []byte(XMLHeader+templateTheme))
  32. f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(XMLHeader+templateSheet))
  33. f.Pkg.Store("xl/styles.xml", []byte(XMLHeader+templateStyles))
  34. f.Pkg.Store("xl/workbook.xml", []byte(XMLHeader+templateWorkbook))
  35. f.Pkg.Store("[Content_Types].xml", []byte(XMLHeader+templateContentTypes))
  36. f.SheetCount = 1
  37. f.CalcChain = f.calcChainReader()
  38. f.Comments = make(map[string]*xlsxComments)
  39. f.ContentTypes = f.contentTypesReader()
  40. f.Drawings = sync.Map{}
  41. f.Styles = f.stylesReader()
  42. f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing)
  43. f.VMLDrawing = make(map[string]*vmlDrawing)
  44. f.WorkBook = f.workbookReader()
  45. f.Relationships = sync.Map{}
  46. f.Relationships.Store("xl/_rels/workbook.xml.rels", f.relsReader("xl/_rels/workbook.xml.rels"))
  47. f.sheetMap["Sheet1"] = "xl/worksheets/sheet1.xml"
  48. ws, _ := f.workSheetReader("Sheet1")
  49. f.Sheet.Store("xl/worksheets/sheet1.xml", ws)
  50. f.Theme = f.themeReader()
  51. return f
  52. }
  53. // Save provides a function to override the spreadsheet with origin path.
  54. func (f *File) Save() error {
  55. if f.Path == "" {
  56. return fmt.Errorf("no path defined for file, consider File.WriteTo or File.Write")
  57. }
  58. return f.SaveAs(f.Path)
  59. }
  60. // SaveAs provides a function to create or update to an spreadsheet at the
  61. // provided path.
  62. func (f *File) SaveAs(name string, opt ...Options) error {
  63. if len(name) > MaxFileNameLength {
  64. return ErrMaxFileNameLength
  65. }
  66. f.Path = name
  67. file, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
  68. if err != nil {
  69. return err
  70. }
  71. defer file.Close()
  72. f.options = nil
  73. for _, o := range opt {
  74. f.options = &o
  75. }
  76. return f.Write(file)
  77. }
  78. // Write provides a function to write to an io.Writer.
  79. func (f *File) Write(w io.Writer) error {
  80. _, err := f.WriteTo(w)
  81. return err
  82. }
  83. // WriteTo implements io.WriterTo to write the file.
  84. func (f *File) WriteTo(w io.Writer) (int64, error) {
  85. if f.options != nil && f.options.Password != "" {
  86. buf, err := f.WriteToBuffer()
  87. if err != nil {
  88. return 0, err
  89. }
  90. return buf.WriteTo(w)
  91. }
  92. if err := f.writeDirectToWriter(w); err != nil {
  93. return 0, err
  94. }
  95. return 0, nil
  96. }
  97. // WriteToBuffer provides a function to get bytes.Buffer from the saved file. And it allocate space in memory. Be careful when the file size is large.
  98. func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
  99. buf := new(bytes.Buffer)
  100. zw := zip.NewWriter(buf)
  101. if err := f.writeToZip(zw); err != nil {
  102. return buf, zw.Close()
  103. }
  104. if f.options != nil && f.options.Password != "" {
  105. if err := zw.Close(); err != nil {
  106. return buf, err
  107. }
  108. b, err := Encrypt(buf.Bytes(), f.options)
  109. if err != nil {
  110. return buf, err
  111. }
  112. buf.Reset()
  113. buf.Write(b)
  114. return buf, nil
  115. }
  116. return buf, zw.Close()
  117. }
  118. // writeDirectToWriter provides a function to write to io.Writer.
  119. func (f *File) writeDirectToWriter(w io.Writer) error {
  120. zw := zip.NewWriter(w)
  121. if err := f.writeToZip(zw); err != nil {
  122. zw.Close()
  123. return err
  124. }
  125. return zw.Close()
  126. }
  127. // writeToZip provides a function to write to zip.Writer
  128. func (f *File) writeToZip(zw *zip.Writer) error {
  129. f.calcChainWriter()
  130. f.commentsWriter()
  131. f.contentTypesWriter()
  132. f.drawingsWriter()
  133. f.vmlDrawingWriter()
  134. f.workBookWriter()
  135. f.workSheetWriter()
  136. f.relsWriter()
  137. f.sharedStringsWriter()
  138. f.styleSheetWriter()
  139. for path, stream := range f.streams {
  140. fi, err := zw.Create(path)
  141. if err != nil {
  142. return err
  143. }
  144. var from io.Reader
  145. from, err = stream.rawData.Reader()
  146. if err != nil {
  147. stream.rawData.Close()
  148. return err
  149. }
  150. _, err = io.Copy(fi, from)
  151. if err != nil {
  152. return err
  153. }
  154. stream.rawData.Close()
  155. }
  156. var err error
  157. f.Pkg.Range(func(path, content interface{}) bool {
  158. if err != nil {
  159. return false
  160. }
  161. if _, ok := f.streams[path.(string)]; ok {
  162. return true
  163. }
  164. var fi io.Writer
  165. fi, err = zw.Create(path.(string))
  166. if err != nil {
  167. return false
  168. }
  169. _, err = fi.Write(content.([]byte))
  170. return true
  171. })
  172. return err
  173. }