This closes #744, the `Save`, `Write` and `WriteTo` function accept saving options

This commit is contained in:
xuri 2022-09-08 22:20:21 +08:00
parent 0c5cdfec18
commit fb1aab7add
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
6 changed files with 44 additions and 30 deletions

View File

@ -48,6 +48,8 @@ func TestEncrypt(t *testing.T) {
cell, err = f.GetCellValue("Sheet1", "A1") cell, err = f.GetCellValue("Sheet1", "A1")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "SECRET", cell) assert.Equal(t, "SECRET", cell)
// Test remove password by save workbook with options
assert.NoError(t, f.Save(Options{Password: ""}))
assert.NoError(t, f.Close()) assert.NoError(t, f.Close())
} }

View File

@ -136,13 +136,13 @@ func newFile() *File {
// OpenReader read data stream from io.Reader and return a populated // OpenReader read data stream from io.Reader and return a populated
// spreadsheet file. // spreadsheet file.
func OpenReader(r io.Reader, opt ...Options) (*File, error) { func OpenReader(r io.Reader, opts ...Options) (*File, error) {
b, err := ioutil.ReadAll(r) b, err := ioutil.ReadAll(r)
if err != nil { if err != nil {
return nil, err return nil, err
} }
f := newFile() f := newFile()
f.options = parseOptions(opt...) f.options = parseOptions(opts...)
if f.options.UnzipSizeLimit == 0 { if f.options.UnzipSizeLimit == 0 {
f.options.UnzipSizeLimit = UnzipSizeLimit f.options.UnzipSizeLimit = UnzipSizeLimit
if f.options.UnzipXMLSizeLimit > f.options.UnzipSizeLimit { if f.options.UnzipXMLSizeLimit > f.options.UnzipSizeLimit {

View File

@ -186,18 +186,15 @@ func TestOpenFile(t *testing.T) {
func TestSaveFile(t *testing.T) { func TestSaveFile(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx")) f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) { assert.NoError(t, err)
t.FailNow()
}
assert.EqualError(t, f.SaveAs(filepath.Join("test", "TestSaveFile.xlsb")), ErrWorkbookFileFormat.Error()) assert.EqualError(t, f.SaveAs(filepath.Join("test", "TestSaveFile.xlsb")), ErrWorkbookFileFormat.Error())
for _, ext := range []string{".xlam", ".xlsm", ".xlsx", ".xltm", ".xltx"} { for _, ext := range []string{".xlam", ".xlsm", ".xlsx", ".xltm", ".xltx"} {
assert.NoError(t, f.SaveAs(filepath.Join("test", fmt.Sprintf("TestSaveFile%s", ext)))) assert.NoError(t, f.SaveAs(filepath.Join("test", fmt.Sprintf("TestSaveFile%s", ext))))
} }
assert.NoError(t, f.Close()) assert.NoError(t, f.Close())
f, err = OpenFile(filepath.Join("test", "TestSaveFile.xlsx")) f, err = OpenFile(filepath.Join("test", "TestSaveFile.xlsx"))
if !assert.NoError(t, err) { assert.NoError(t, err)
t.FailNow()
}
assert.NoError(t, f.Save()) assert.NoError(t, f.Save())
assert.NoError(t, f.Close()) assert.NoError(t, f.Close())
} }

42
file.go
View File

@ -55,44 +55,32 @@ func NewFile() *File {
} }
// Save provides a function to override the spreadsheet with origin path. // Save provides a function to override the spreadsheet with origin path.
func (f *File) Save() error { func (f *File) Save(opts ...Options) error {
if f.Path == "" { if f.Path == "" {
return ErrSave return ErrSave
} }
if f.options != nil { for i := range opts {
return f.SaveAs(f.Path, *f.options) f.options = &opts[i]
} }
return f.SaveAs(f.Path) return f.SaveAs(f.Path, *f.options)
} }
// SaveAs provides a function to create or update to a spreadsheet at the // SaveAs provides a function to create or update to a spreadsheet at the
// provided path. // provided path.
func (f *File) SaveAs(name string, opt ...Options) error { func (f *File) SaveAs(name string, opts ...Options) error {
if len(name) > MaxFilePathLength { if len(name) > MaxFilePathLength {
return ErrMaxFilePathLength return ErrMaxFilePathLength
} }
f.Path = name f.Path = name
contentType, ok := map[string]string{ if _, ok := supportedContentType[filepath.Ext(f.Path)]; !ok {
".xlam": ContentTypeAddinMacro,
".xlsm": ContentTypeMacro,
".xlsx": ContentTypeSheetML,
".xltm": ContentTypeTemplateMacro,
".xltx": ContentTypeTemplate,
}[filepath.Ext(f.Path)]
if !ok {
return ErrWorkbookFileFormat return ErrWorkbookFileFormat
} }
f.setContentTypePartProjectExtensions(contentType)
file, err := os.OpenFile(filepath.Clean(name), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm) file, err := os.OpenFile(filepath.Clean(name), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm)
if err != nil { if err != nil {
return err return err
} }
defer file.Close() defer file.Close()
f.options = nil return f.Write(file, opts...)
for i := range opt {
f.options = &opt[i]
}
return f.Write(file)
} }
// Close closes and cleanup the open temporary file for the spreadsheet. // Close closes and cleanup the open temporary file for the spreadsheet.
@ -113,13 +101,23 @@ func (f *File) Close() error {
} }
// Write provides a function to write to an io.Writer. // Write provides a function to write to an io.Writer.
func (f *File) Write(w io.Writer) error { func (f *File) Write(w io.Writer, opts ...Options) error {
_, err := f.WriteTo(w) _, err := f.WriteTo(w, opts...)
return err return err
} }
// WriteTo implements io.WriterTo to write the file. // WriteTo implements io.WriterTo to write the file.
func (f *File) WriteTo(w io.Writer) (int64, error) { func (f *File) WriteTo(w io.Writer, opts ...Options) (int64, error) {
for i := range opts {
f.options = &opts[i]
}
if len(f.Path) != 0 {
contentType, ok := supportedContentType[filepath.Ext(f.Path)]
if !ok {
return 0, ErrWorkbookFileFormat
}
f.setContentTypePartProjectExtensions(contentType)
}
if f.options != nil && f.options.Password != "" { if f.options != nil && f.options.Password != "" {
buf, err := f.WriteToBuffer() buf, err := f.WriteToBuffer()
if err != nil { if err != nil {

View File

@ -71,6 +71,14 @@ func TestWriteTo(t *testing.T) {
_, err := f.WriteTo(bufio.NewWriter(&buf)) _, err := f.WriteTo(bufio.NewWriter(&buf))
assert.EqualError(t, err, "zip: FileHeader.Name too long") assert.EqualError(t, err, "zip: FileHeader.Name too long")
} }
// Test write with unsupported workbook file format
{
f, buf := File{Pkg: sync.Map{}}, bytes.Buffer{}
f.Pkg.Store("/d", []byte("s"))
f.Path = "Book1.xls"
_, err := f.WriteTo(bufio.NewWriter(&buf))
assert.EqualError(t, err, ErrWorkbookFileFormat.Error())
}
} }
func TestClose(t *testing.T) { func TestClose(t *testing.T) {

View File

@ -144,6 +144,15 @@ const (
// supportedImageTypes defined supported image types. // supportedImageTypes defined supported image types.
var supportedImageTypes = map[string]string{".gif": ".gif", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png", ".tif": ".tiff", ".tiff": ".tiff", ".emf": ".emf", ".wmf": ".wmf", ".emz": ".emz", ".wmz": ".wmz"} var supportedImageTypes = map[string]string{".gif": ".gif", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png", ".tif": ".tiff", ".tiff": ".tiff", ".emf": ".emf", ".wmf": ".wmf", ".emz": ".emz", ".wmz": ".wmz"}
// supportedContentType defined supported file format types.
var supportedContentType = map[string]string{
".xlam": ContentTypeAddinMacro,
".xlsm": ContentTypeMacro,
".xlsx": ContentTypeSheetML,
".xltm": ContentTypeTemplateMacro,
".xltx": ContentTypeTemplate,
}
// xlsxCNvPr directly maps the cNvPr (Non-Visual Drawing Properties). This // xlsxCNvPr directly maps the cNvPr (Non-Visual Drawing Properties). This
// element specifies non-visual canvas properties. This allows for additional // element specifies non-visual canvas properties. This allows for additional
// information that does not affect the appearance of the picture to be stored. // information that does not affect the appearance of the picture to be stored.