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")
assert.NoError(t, err)
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())
}

View File

@ -136,13 +136,13 @@ func newFile() *File {
// OpenReader read data stream from io.Reader and return a populated
// 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)
if err != nil {
return nil, err
}
f := newFile()
f.options = parseOptions(opt...)
f.options = parseOptions(opts...)
if f.options.UnzipSizeLimit == 0 {
f.options.UnzipSizeLimit = UnzipSizeLimit
if f.options.UnzipXMLSizeLimit > f.options.UnzipSizeLimit {

View File

@ -186,18 +186,15 @@ func TestOpenFile(t *testing.T) {
func TestSaveFile(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
assert.NoError(t, err)
assert.EqualError(t, f.SaveAs(filepath.Join("test", "TestSaveFile.xlsb")), ErrWorkbookFileFormat.Error())
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.Close())
f, err = OpenFile(filepath.Join("test", "TestSaveFile.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
assert.NoError(t, err)
assert.NoError(t, f.Save())
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.
func (f *File) Save() error {
func (f *File) Save(opts ...Options) error {
if f.Path == "" {
return ErrSave
}
if f.options != nil {
return f.SaveAs(f.Path, *f.options)
for i := range opts {
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
// provided path.
func (f *File) SaveAs(name string, opt ...Options) error {
func (f *File) SaveAs(name string, opts ...Options) error {
if len(name) > MaxFilePathLength {
return ErrMaxFilePathLength
}
f.Path = name
contentType, ok := map[string]string{
".xlam": ContentTypeAddinMacro,
".xlsm": ContentTypeMacro,
".xlsx": ContentTypeSheetML,
".xltm": ContentTypeTemplateMacro,
".xltx": ContentTypeTemplate,
}[filepath.Ext(f.Path)]
if !ok {
if _, ok := supportedContentType[filepath.Ext(f.Path)]; !ok {
return ErrWorkbookFileFormat
}
f.setContentTypePartProjectExtensions(contentType)
file, err := os.OpenFile(filepath.Clean(name), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm)
if err != nil {
return err
}
defer file.Close()
f.options = nil
for i := range opt {
f.options = &opt[i]
}
return f.Write(file)
return f.Write(file, opts...)
}
// 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.
func (f *File) Write(w io.Writer) error {
_, err := f.WriteTo(w)
func (f *File) Write(w io.Writer, opts ...Options) error {
_, err := f.WriteTo(w, opts...)
return err
}
// 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 != "" {
buf, err := f.WriteToBuffer()
if err != nil {

View File

@ -71,6 +71,14 @@ func TestWriteTo(t *testing.T) {
_, err := f.WriteTo(bufio.NewWriter(&buf))
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) {

View File

@ -144,6 +144,15 @@ const (
// 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"}
// 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
// element specifies non-visual canvas properties. This allows for additional
// information that does not affect the appearance of the picture to be stored.