@@ -30,7 +30,7 @@ type StreamWriter struct {
30
30
SheetID int
31
31
sheetWritten bool
32
32
worksheet * xlsxWorksheet
33
- rawData bufferedWriter
33
+ rawData TmpFile
34
34
rows int
35
35
mergeCellsCount int
36
36
mergeCells strings.Builder
@@ -119,11 +119,17 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
119
119
if sheetID == - 1 {
120
120
return nil , ErrSheetNotExist {sheet }
121
121
}
122
+
123
+ rawData := TmpFile (newBufferedWriter (f .options .TmpDir , nil ))
124
+ if f .options .StreamingTmpFile != nil {
125
+ rawData = * f .options .StreamingTmpFile
126
+ }
127
+
122
128
sw := & StreamWriter {
123
129
file : f ,
124
130
Sheet : sheet ,
125
131
SheetID : sheetID ,
126
- rawData : bufferedWriter { tmpDir : f . options . TmpDir } ,
132
+ rawData : rawData ,
127
133
}
128
134
var err error
129
135
sw .worksheet , err = f .workSheetReader (sheet )
@@ -138,7 +144,7 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
138
144
f .streams [sheetXMLPath ] = sw
139
145
140
146
_ , _ = sw .rawData .WriteString (xml .Header + `<worksheet` + templateNamespaceIDMap )
141
- bulkAppendFields (& sw .rawData , sw .worksheet , 3 , 4 )
147
+ bulkAppendFields (sw .rawData , sw .worksheet , 3 , 4 )
142
148
return sw , err
143
149
}
144
150
@@ -429,7 +435,7 @@ func (sw *StreamWriter) SetRow(cell string, values []interface{}, opts ...RowOpt
429
435
_ , _ = sw .rawData .WriteString (`</row>` )
430
436
return err
431
437
}
432
- writeCell (& sw .rawData , c )
438
+ writeCell (sw .rawData , c )
433
439
}
434
440
_ , _ = sw .rawData .WriteString (`</row>` )
435
441
return sw .rawData .Sync ()
@@ -602,7 +608,7 @@ func setCellIntFunc(c *xlsxC, val interface{}) {
602
608
}
603
609
604
610
// writeCell constructs a cell XML and writes it to the buffer.
605
- func writeCell (buf * bufferedWriter , c xlsxC ) {
611
+ func writeCell (buf TmpFile , c xlsxC ) {
606
612
_ , _ = buf .WriteString (`<c` )
607
613
if c .XMLSpace .Value != "" {
608
614
_ , _ = buf .WriteString (` xml:` )
@@ -663,7 +669,7 @@ func writeCell(buf *bufferedWriter, c xlsxC) {
663
669
// sheetData XML start element to the buffer.
664
670
func (sw * StreamWriter ) writeSheetData () {
665
671
if ! sw .sheetWritten {
666
- bulkAppendFields (& sw .rawData , sw .worksheet , 5 , 6 )
672
+ bulkAppendFields (sw .rawData , sw .worksheet , 5 , 6 )
667
673
if sw .worksheet .Cols != nil {
668
674
_ , _ = sw .rawData .WriteString ("<cols>" )
669
675
for _ , col := range sw .worksheet .Cols .Col {
@@ -695,7 +701,7 @@ func (sw *StreamWriter) writeSheetData() {
695
701
func (sw * StreamWriter ) Flush () error {
696
702
sw .writeSheetData ()
697
703
_ , _ = sw .rawData .WriteString (`</sheetData>` )
698
- bulkAppendFields (& sw .rawData , sw .worksheet , 9 , 16 )
704
+ bulkAppendFields (sw .rawData , sw .worksheet , 9 , 16 )
699
705
mergeCells := strings.Builder {}
700
706
if sw .mergeCellsCount > 0 {
701
707
_ , _ = mergeCells .WriteString (`<mergeCells count="` )
@@ -705,9 +711,9 @@ func (sw *StreamWriter) Flush() error {
705
711
_ , _ = mergeCells .WriteString (`</mergeCells>` )
706
712
}
707
713
_ , _ = sw .rawData .WriteString (mergeCells .String ())
708
- bulkAppendFields (& sw .rawData , sw .worksheet , 18 , 39 )
714
+ bulkAppendFields (sw .rawData , sw .worksheet , 18 , 39 )
709
715
_ , _ = sw .rawData .WriteString (sw .tableParts )
710
- bulkAppendFields (& sw .rawData , sw .worksheet , 41 , 41 )
716
+ bulkAppendFields (sw .rawData , sw .worksheet , 41 , 41 )
711
717
_ , _ = sw .rawData .WriteString (`</worksheet>` )
712
718
if err := sw .rawData .Flush (); err != nil {
713
719
return err
@@ -733,11 +739,38 @@ func bulkAppendFields(w io.Writer, ws *xlsxWorksheet, from, to int) {
733
739
}
734
740
}
735
741
742
+ // TmpFile is an interface for a streaming writer temporary file abstraction, implement it to support
743
+ // custom temporary file storage.
744
+ type TmpFile interface {
745
+ Close () error
746
+ Reader () (io.Reader , error )
747
+ Sync () error
748
+ Write (p []byte ) (n int , err error )
749
+ WriteString (s string ) (n int , err error )
750
+ Flush () error
751
+ }
752
+
753
+ // newBufferedWriter create a new bufferedWriter, which will write to a temp
754
+ // file if the buffer size exceeds the chunkSize. when chunkSize is nil, the
755
+ // default chunkSize which is StreamChunkSize will be used.
756
+ func newBufferedWriter (tmpDir string , chunkSize * int ) * bufferedWriter {
757
+ tarChunkSize := StreamChunkSize
758
+ if chunkSize != nil {
759
+ tarChunkSize = * chunkSize
760
+ }
761
+ return & bufferedWriter {
762
+ chunkSize : tarChunkSize ,
763
+ tmpDir : tmpDir ,
764
+ }
765
+ }
766
+
736
767
// bufferedWriter uses a temp file to store an extended buffer. Writes are
737
768
// always made to an in-memory buffer, which will always succeed. The buffer
738
769
// is written to the temp file with Sync, which may return an error.
739
770
// Therefore, Sync should be periodically called and the error checked.
740
771
type bufferedWriter struct {
772
+ chunkSize int
773
+
741
774
tmpDir string
742
775
tmp * os.File
743
776
buf bytes.Buffer
0 commit comments