file.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright 2016 - 2023 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 and
  6. // read from XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and
  7. // writing spreadsheet documents generated by Microsoft Excel™ 2007 and later.
  8. // Supports complex components by high compatibility, and provided streaming
  9. // API for generating or reading data from a worksheet with huge amounts of
  10. // data. This library needs Go version 1.16 or later.
  11. package excelize
  12. import (
  13. "archive/zip"
  14. "bytes"
  15. "encoding/xml"
  16. "io"
  17. "os"
  18. "path/filepath"
  19. "strings"
  20. "sync"
  21. )
  22. // NewFile provides a function to create new file by default template.
  23. // For example:
  24. //
  25. // f := NewFile()
  26. func NewFile() *File {
  27. f := newFile()
  28. f.Pkg.Store("_rels/.rels", []byte(xml.Header+templateRels))
  29. f.Pkg.Store(defaultXMLPathDocPropsApp, []byte(xml.Header+templateDocpropsApp))
  30. f.Pkg.Store(defaultXMLPathDocPropsCore, []byte(xml.Header+templateDocpropsCore))
  31. f.Pkg.Store(defaultXMLPathWorkbookRels, []byte(xml.Header+templateWorkbookRels))
  32. f.Pkg.Store("xl/theme/theme1.xml", []byte(xml.Header+templateTheme))
  33. f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(xml.Header+templateSheet))
  34. f.Pkg.Store(defaultXMLPathStyles, []byte(xml.Header+templateStyles))
  35. f.Pkg.Store(defaultXMLPathWorkbook, []byte(xml.Header+templateWorkbook))
  36. f.Pkg.Store(defaultXMLPathContentTypes, []byte(xml.Header+templateContentTypes))
  37. f.SheetCount = 1
  38. f.CalcChain, _ = f.calcChainReader()
  39. f.ContentTypes, _ = f.contentTypesReader()
  40. f.Styles, _ = f.stylesReader()
  41. f.WorkBook, _ = f.workbookReader()
  42. f.Relationships = sync.Map{}
  43. rels, _ := f.relsReader(defaultXMLPathWorkbookRels)
  44. f.Relationships.Store(defaultXMLPathWorkbookRels, rels)
  45. f.sheetMap["Sheet1"] = "xl/worksheets/sheet1.xml"
  46. ws, _ := f.workSheetReader("Sheet1")
  47. f.Sheet.Store("xl/worksheets/sheet1.xml", ws)
  48. f.Theme, _ = f.themeReader()
  49. return f
  50. }
  51. // Save provides a function to override the spreadsheet with origin path.
  52. func (f *File) Save(opts ...Options) error {
  53. if f.Path == "" {
  54. return ErrSave
  55. }
  56. for i := range opts {
  57. f.options = &opts[i]
  58. }
  59. return f.SaveAs(f.Path, *f.options)
  60. }
  61. // SaveAs provides a function to create or update to a spreadsheet at the
  62. // provided path.
  63. func (f *File) SaveAs(name string, opts ...Options) error {
  64. if len(name) > MaxFilePathLength {
  65. return ErrMaxFilePathLength
  66. }
  67. f.Path = name
  68. if _, ok := supportedContentTypes[strings.ToLower(filepath.Ext(f.Path))]; !ok {
  69. return ErrWorkbookFileFormat
  70. }
  71. file, err := os.OpenFile(filepath.Clean(name), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm)
  72. if err != nil {
  73. return err
  74. }
  75. defer file.Close()
  76. return f.Write(file, opts...)
  77. }
  78. // Close closes and cleanup the open temporary file for the spreadsheet.
  79. func (f *File) Close() error {
  80. var err error
  81. if f.sharedStringTemp != nil {
  82. if err := f.sharedStringTemp.Close(); err != nil {
  83. return err
  84. }
  85. }
  86. f.tempFiles.Range(func(k, v interface{}) bool {
  87. if err = os.Remove(v.(string)); err != nil {
  88. return false
  89. }
  90. return true
  91. })
  92. for _, stream := range f.streams {
  93. _ = stream.rawData.Close()
  94. }
  95. return err
  96. }
  97. // Write provides a function to write to an io.Writer.
  98. func (f *File) Write(w io.Writer, opts ...Options) error {
  99. _, err := f.WriteTo(w, opts...)
  100. return err
  101. }
  102. // WriteTo implements io.WriterTo to write the file.
  103. func (f *File) WriteTo(w io.Writer, opts ...Options) (int64, error) {
  104. for i := range opts {
  105. f.options = &opts[i]
  106. }
  107. if len(f.Path) != 0 {
  108. contentType, ok := supportedContentTypes[strings.ToLower(filepath.Ext(f.Path))]
  109. if !ok {
  110. return 0, ErrWorkbookFileFormat
  111. }
  112. if err := f.setContentTypePartProjectExtensions(contentType); err != nil {
  113. return 0, err
  114. }
  115. }
  116. if f.options != nil && f.options.Password != "" {
  117. buf, err := f.WriteToBuffer()
  118. if err != nil {
  119. return 0, err
  120. }
  121. return buf.WriteTo(w)
  122. }
  123. if err := f.writeDirectToWriter(w); err != nil {
  124. return 0, err
  125. }
  126. return 0, nil
  127. }
  128. // WriteToBuffer provides a function to get bytes.Buffer from the saved file,
  129. // and it allocates space in memory. Be careful when the file size is large.
  130. func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
  131. buf := new(bytes.Buffer)
  132. zw := zip.NewWriter(buf)
  133. if err := f.writeToZip(zw); err != nil {
  134. return buf, zw.Close()
  135. }
  136. if f.options != nil && f.options.Password != "" {
  137. if err := zw.Close(); err != nil {
  138. return buf, err
  139. }
  140. b, err := Encrypt(buf.Bytes(), f.options)
  141. if err != nil {
  142. return buf, err
  143. }
  144. buf.Reset()
  145. buf.Write(b)
  146. return buf, nil
  147. }
  148. return buf, zw.Close()
  149. }
  150. // writeDirectToWriter provides a function to write to io.Writer.
  151. func (f *File) writeDirectToWriter(w io.Writer) error {
  152. zw := zip.NewWriter(w)
  153. if err := f.writeToZip(zw); err != nil {
  154. _ = zw.Close()
  155. return err
  156. }
  157. return zw.Close()
  158. }
  159. // writeToZip provides a function to write to zip.Writer
  160. func (f *File) writeToZip(zw *zip.Writer) error {
  161. f.calcChainWriter()
  162. f.commentsWriter()
  163. f.contentTypesWriter()
  164. f.drawingsWriter()
  165. f.vmlDrawingWriter()
  166. f.workBookWriter()
  167. f.workSheetWriter()
  168. f.relsWriter()
  169. _ = f.sharedStringsLoader()
  170. f.sharedStringsWriter()
  171. f.styleSheetWriter()
  172. f.themeWriter()
  173. for path, stream := range f.streams {
  174. fi, err := zw.Create(path)
  175. if err != nil {
  176. return err
  177. }
  178. var from io.Reader
  179. from, err = stream.rawData.Reader()
  180. if err != nil {
  181. _ = stream.rawData.Close()
  182. return err
  183. }
  184. _, err = io.Copy(fi, from)
  185. if err != nil {
  186. return err
  187. }
  188. }
  189. var err error
  190. f.Pkg.Range(func(path, content interface{}) bool {
  191. if err != nil {
  192. return false
  193. }
  194. if _, ok := f.streams[path.(string)]; ok {
  195. return true
  196. }
  197. var fi io.Writer
  198. fi, err = zw.Create(path.(string))
  199. if err != nil {
  200. return false
  201. }
  202. _, err = fi.Write(content.([]byte))
  203. return true
  204. })
  205. f.tempFiles.Range(func(path, content interface{}) bool {
  206. if _, ok := f.Pkg.Load(path); ok {
  207. return true
  208. }
  209. var fi io.Writer
  210. fi, err = zw.Create(path.(string))
  211. if err != nil {
  212. return false
  213. }
  214. _, err = fi.Write(f.readBytes(path.(string)))
  215. return true
  216. })
  217. return err
  218. }