Skip to content

Commit 845a274

Browse files
authored
This closes #2199, add new function SetZipWriter for custom ZIP writer support (#2200)
- Add new ZipWriter data type - Add new field ZipWriter in the File data type - Made the CharsetTranscoder function parameter does not use the internal data type charsetTranscoderFn - Update unit tests
1 parent b372bd3 commit 845a274

File tree

4 files changed

+33
-12
lines changed

4 files changed

+33
-12
lines changed

excelize.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"bytes"
1818
"encoding/xml"
1919
"io"
20+
"io/fs"
2021
"os"
2122
"path/filepath"
2223
"strconv"
@@ -41,7 +42,7 @@ type File struct {
4142
tempFiles sync.Map
4243
xmlAttr sync.Map
4344
CalcChain *xlsxCalcChain
44-
CharsetReader charsetTranscoderFn
45+
CharsetReader func(charset string, input io.Reader) (rdr io.Reader, err error)
4546
Comments map[string]*xlsxComments
4647
ContentTypes *xlsxTypes
4748
DecodeVMLDrawing map[string]*decodeVmlDrawing
@@ -58,11 +59,17 @@ type File struct {
5859
VMLDrawing map[string]*vmlDrawing
5960
VolatileDeps *xlsxVolTypes
6061
WorkBook *xlsxWorkbook
62+
ZipWriter func(io.Writer) ZipWriter
6163
}
6264

63-
// charsetTranscoderFn set user-defined codepage transcoder function for open
64-
// the spreadsheet from non-UTF-8 encoding.
65-
type charsetTranscoderFn func(charset string, input io.Reader) (rdr io.Reader, err error)
65+
// ZipWriter defines an interface for writing files to a ZIP archive. It
66+
// provides methods to create new files within the archive, add files from a
67+
// filesystem, and close the archive when writing is complete.
68+
type ZipWriter interface {
69+
Create(name string) (io.Writer, error)
70+
AddFS(fsys fs.FS) error
71+
Close() error
72+
}
6673

6774
// Options define the options for opening and reading the spreadsheet.
6875
//
@@ -153,6 +160,7 @@ func newFile() *File {
153160
VMLDrawing: make(map[string]*vmlDrawing),
154161
Relationships: sync.Map{},
155162
CharsetReader: charset.NewReaderLabel,
163+
ZipWriter: func(w io.Writer) ZipWriter { return zip.NewWriter(w) },
156164
}
157165
}
158166

@@ -232,9 +240,15 @@ func (f *File) getOptions(opts ...Options) *Options {
232240
return options
233241
}
234242

235-
// CharsetTranscoder Set user defined codepage transcoder function for open
243+
// CharsetTranscoder set user defined codepage transcoder function for open
236244
// workbook from non UTF-8 encoding.
237-
func (f *File) CharsetTranscoder(fn charsetTranscoderFn) *File { f.CharsetReader = fn; return f }
245+
func (f *File) CharsetTranscoder(fn func(charset string, input io.Reader) (rdr io.Reader, err error)) *File {
246+
f.CharsetReader = fn
247+
return f
248+
}
249+
250+
// SetZipWriter set user defined zip writer function for saving the workbook.
251+
func (f *File) SetZipWriter(fn func(io.Writer) ZipWriter) *File { f.ZipWriter = fn; return f }
238252

239253
// Creates new XML decoder with charset reader.
240254
func (f *File) xmlNewDecoder(rdr io.Reader) (ret *xml.Decoder) {

excelize_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"time"
2222

2323
"github.com/stretchr/testify/assert"
24+
"golang.org/x/net/html/charset"
2425
)
2526

2627
func TestOpenFile(t *testing.T) {
@@ -244,7 +245,7 @@ func TestSaveAsWrongPath(t *testing.T) {
244245

245246
func TestCharsetTranscoder(t *testing.T) {
246247
f := NewFile()
247-
f.CharsetTranscoder(*new(charsetTranscoderFn))
248+
f.CharsetTranscoder(charset.NewReaderLabel)
248249
}
249250

250251
func TestOpenReader(t *testing.T) {
@@ -355,7 +356,7 @@ func TestOpenReader(t *testing.T) {
355356

356357
func TestBrokenFile(t *testing.T) {
357358
// Test write file with broken file struct
358-
f := File{}
359+
f := File{ZipWriter: func(w io.Writer) ZipWriter { return zip.NewWriter(w) }}
359360

360361
t.Run("SaveWithoutName", func(t *testing.T) {
361362
assert.EqualError(t, f.Save(), "no path defined for file, consider File.WriteTo or File.Write")

file.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
package excelize
1313

1414
import (
15-
"archive/zip"
1615
"bytes"
1716
"encoding/binary"
1817
"encoding/xml"
@@ -137,7 +136,7 @@ func (f *File) WriteTo(w io.Writer, opts ...Options) (int64, error) {
137136
// and it allocates space in memory. Be careful when the file size is large.
138137
func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
139138
buf := new(bytes.Buffer)
140-
zw := zip.NewWriter(buf)
139+
zw := f.ZipWriter(buf)
141140

142141
if err := f.writeToZip(zw); err != nil {
143142
_ = zw.Close()
@@ -158,8 +157,8 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
158157
return buf, nil
159158
}
160159

161-
// writeToZip provides a function to write to zip.Writer
162-
func (f *File) writeToZip(zw *zip.Writer) error {
160+
// writeToZip provides a function to write to ZipWriter.
161+
func (f *File) writeToZip(zw ZipWriter) error {
163162
f.calcChainWriter()
164163
f.commentsWriter()
165164
f.contentTypesWriter()

file_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package excelize
22

33
import (
4+
"archive/zip"
45
"bufio"
56
"bytes"
67
"encoding/binary"
8+
"io"
79
"math"
810
"os"
911
"path/filepath"
@@ -43,6 +45,7 @@ func TestWriteTo(t *testing.T) {
4345
// Test WriteToBuffer err
4446
{
4547
f, buf := File{Pkg: sync.Map{}}, bytes.Buffer{}
48+
f.SetZipWriter(func(w io.Writer) ZipWriter { return zip.NewWriter(w) })
4649
f.Pkg.Store("/d/", []byte("s"))
4750
_, err := f.WriteTo(bufio.NewWriter(&buf))
4851
assert.EqualError(t, err, "zip: write to directory")
@@ -51,6 +54,7 @@ func TestWriteTo(t *testing.T) {
5154
// Test file path overflow
5255
{
5356
f, buf := File{Pkg: sync.Map{}}, bytes.Buffer{}
57+
f.SetZipWriter(func(w io.Writer) ZipWriter { return zip.NewWriter(w) })
5458
const maxUint16 = 1<<16 - 1
5559
f.Pkg.Store(strings.Repeat("s", maxUint16+1), nil)
5660
_, err := f.WriteTo(bufio.NewWriter(&buf))
@@ -59,6 +63,7 @@ func TestWriteTo(t *testing.T) {
5963
// Test StreamsWriter err
6064
{
6165
f, buf := File{Pkg: sync.Map{}}, bytes.Buffer{}
66+
f.SetZipWriter(func(w io.Writer) ZipWriter { return zip.NewWriter(w) })
6267
f.Pkg.Store("s", nil)
6368
f.streams = make(map[string]*StreamWriter)
6469
file, _ := os.Open("123")
@@ -69,6 +74,7 @@ func TestWriteTo(t *testing.T) {
6974
// Test write with temporary file
7075
{
7176
f, buf := File{tempFiles: sync.Map{}}, bytes.Buffer{}
77+
f.SetZipWriter(func(w io.Writer) ZipWriter { return zip.NewWriter(w) })
7278
const maxUint16 = 1<<16 - 1
7379
f.tempFiles.Store("s", "")
7480
f.tempFiles.Store(strings.Repeat("s", maxUint16+1), "")
@@ -78,6 +84,7 @@ func TestWriteTo(t *testing.T) {
7884
// Test write with unsupported workbook file format
7985
{
8086
f, buf := File{Pkg: sync.Map{}}, bytes.Buffer{}
87+
f.SetZipWriter(func(w io.Writer) ZipWriter { return zip.NewWriter(w) })
8188
f.Pkg.Store("/d", []byte("s"))
8289
f.Path = "Book1.xls"
8390
_, err := f.WriteTo(bufio.NewWriter(&buf))

0 commit comments

Comments
 (0)