This closes #1379, cleanup stream writer temporary files by the `Close` function

- Fix error on inserting columns or rows on the worksheet which contains one cell merged cell range
- Fix getting incomplete rich text cell value in some cases
- Unit tests updated
This commit is contained in:
xuri 2022-10-26 00:04:23 +08:00
parent f44153ea46
commit adf9d37d82
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
6 changed files with 67 additions and 14 deletions

View File

@ -278,7 +278,11 @@ func (f *File) adjustMergeCells(ws *xlsxWorksheet, dir adjustDirection, num, off
for i := 0; i < len(ws.MergeCells.Cells); i++ { for i := 0; i < len(ws.MergeCells.Cells); i++ {
mergedCells := ws.MergeCells.Cells[i] mergedCells := ws.MergeCells.Cells[i]
coordinates, err := rangeRefToCoordinates(mergedCells.Ref) mergedCellsRef := mergedCells.Ref
if !strings.Contains(mergedCellsRef, ":") {
mergedCellsRef += ":" + mergedCellsRef
}
coordinates, err := rangeRefToCoordinates(mergedCellsRef)
if err != nil { if err != nil {
return err return err
} }

View File

@ -47,6 +47,15 @@ func TestAdjustMergeCells(t *testing.T) {
}, },
}, },
}, columns, 1, -1)) }, columns, 1, -1))
assert.NoError(t, f.adjustMergeCells(&xlsxWorksheet{
MergeCells: &xlsxMergeCells{
Cells: []*xlsxMergeCell{
{
Ref: "A2",
},
},
},
}, columns, 1, -1))
// testing adjustMergeCells // testing adjustMergeCells
var cases []struct { var cases []struct {

22
cell.go
View File

@ -152,19 +152,19 @@ func (f *File) SetCellValue(sheet, cell string, value interface{}) error {
// String extracts characters from a string item. // String extracts characters from a string item.
func (x xlsxSI) String() string { func (x xlsxSI) String() string {
if len(x.R) > 0 { var value strings.Builder
var rows strings.Builder
for _, s := range x.R {
if s.T != nil {
rows.WriteString(s.T.Val)
}
}
return bstrUnmarshal(rows.String())
}
if x.T != nil { if x.T != nil {
return bstrUnmarshal(x.T.Val) value.WriteString(x.T.Val)
} }
return "" for _, s := range x.R {
if s.T != nil {
value.WriteString(s.T.Val)
}
}
if value.Len() == 0 {
return ""
}
return bstrUnmarshal(value.String())
} }
// hasValue determine if cell non-blank value. // hasValue determine if cell non-blank value.

View File

@ -97,6 +97,9 @@ func (f *File) Close() error {
} }
return true return true
}) })
for _, stream := range f.streams {
_ = stream.rawData.Close()
}
return err return err
} }
@ -195,7 +198,6 @@ func (f *File) writeToZip(zw *zip.Writer) error {
if err != nil { if err != nil {
return err return err
} }
_ = stream.rawData.Close()
} }
var err error var err error
f.Pkg.Range(func(path, content interface{}) bool { f.Pkg.Range(func(path, content interface{}) bool {

View File

@ -48,6 +48,11 @@ type StreamWriter struct {
// with numbers and style: // with numbers and style:
// //
// file := excelize.NewFile() // file := excelize.NewFile()
// defer func() {
// if err := file.Close(); err != nil {
// fmt.Println(err)
// }
// }()
// streamWriter, err := file.NewStreamWriter("Sheet1") // streamWriter, err := file.NewStreamWriter("Sheet1")
// if err != nil { // if err != nil {
// fmt.Println(err) // fmt.Println(err)

View File

@ -15,7 +15,11 @@ import (
func BenchmarkStreamWriter(b *testing.B) { func BenchmarkStreamWriter(b *testing.B) {
file := NewFile() file := NewFile()
defer func() {
if err := file.Close(); err != nil {
b.Error(err)
}
}()
row := make([]interface{}, 10) row := make([]interface{}, 10)
for colID := 0; colID < 10; colID++ { for colID := 0; colID < 10; colID++ {
row[colID] = colID row[colID] = colID
@ -78,6 +82,7 @@ func TestStreamWriter(t *testing.T) {
// Test set cell column overflow. // Test set cell column overflow.
assert.ErrorIs(t, streamWriter.SetRow("XFD51201", []interface{}{"A", "B", "C"}), ErrColumnNumber) assert.ErrorIs(t, streamWriter.SetRow("XFD51201", []interface{}{"A", "B", "C"}), ErrColumnNumber)
assert.NoError(t, file.Close())
// Test close temporary file error. // Test close temporary file error.
file = NewFile() file = NewFile()
@ -107,6 +112,7 @@ func TestStreamWriter(t *testing.T) {
file.Pkg.Store("xl/worksheets/sheet1.xml", MacintoshCyrillicCharset) file.Pkg.Store("xl/worksheets/sheet1.xml", MacintoshCyrillicCharset)
_, err = file.NewStreamWriter("Sheet1") _, err = file.NewStreamWriter("Sheet1")
assert.EqualError(t, err, "xml decode error: XML syntax error on line 1: invalid UTF-8") assert.EqualError(t, err, "xml decode error: XML syntax error on line 1: invalid UTF-8")
assert.NoError(t, file.Close())
// Test read cell. // Test read cell.
file = NewFile() file = NewFile()
@ -138,6 +144,9 @@ func TestStreamWriter(t *testing.T) {
func TestStreamSetColWidth(t *testing.T) { func TestStreamSetColWidth(t *testing.T) {
file := NewFile() file := NewFile()
defer func() {
assert.NoError(t, file.Close())
}()
streamWriter, err := file.NewStreamWriter("Sheet1") streamWriter, err := file.NewStreamWriter("Sheet1")
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, streamWriter.SetColWidth(3, 2, 20)) assert.NoError(t, streamWriter.SetColWidth(3, 2, 20))
@ -150,6 +159,9 @@ func TestStreamSetColWidth(t *testing.T) {
func TestStreamSetPanes(t *testing.T) { func TestStreamSetPanes(t *testing.T) {
file, paneOpts := NewFile(), `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}` file, paneOpts := NewFile(), `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`
defer func() {
assert.NoError(t, file.Close())
}()
streamWriter, err := file.NewStreamWriter("Sheet1") streamWriter, err := file.NewStreamWriter("Sheet1")
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, streamWriter.SetPanes(paneOpts)) assert.NoError(t, streamWriter.SetPanes(paneOpts))
@ -160,6 +172,9 @@ func TestStreamSetPanes(t *testing.T) {
func TestStreamTable(t *testing.T) { func TestStreamTable(t *testing.T) {
file := NewFile() file := NewFile()
defer func() {
assert.NoError(t, file.Close())
}()
streamWriter, err := file.NewStreamWriter("Sheet1") streamWriter, err := file.NewStreamWriter("Sheet1")
assert.NoError(t, err) assert.NoError(t, err)
@ -194,6 +209,9 @@ func TestStreamTable(t *testing.T) {
func TestStreamMergeCells(t *testing.T) { func TestStreamMergeCells(t *testing.T) {
file := NewFile() file := NewFile()
defer func() {
assert.NoError(t, file.Close())
}()
streamWriter, err := file.NewStreamWriter("Sheet1") streamWriter, err := file.NewStreamWriter("Sheet1")
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, streamWriter.MergeCell("A1", "D1")) assert.NoError(t, streamWriter.MergeCell("A1", "D1"))
@ -207,6 +225,9 @@ func TestStreamMergeCells(t *testing.T) {
func TestNewStreamWriter(t *testing.T) { func TestNewStreamWriter(t *testing.T) {
// Test error exceptions // Test error exceptions
file := NewFile() file := NewFile()
defer func() {
assert.NoError(t, file.Close())
}()
_, err := file.NewStreamWriter("Sheet1") _, err := file.NewStreamWriter("Sheet1")
assert.NoError(t, err) assert.NoError(t, err)
_, err = file.NewStreamWriter("SheetN") _, err = file.NewStreamWriter("SheetN")
@ -223,6 +244,9 @@ func TestStreamMarshalAttrs(t *testing.T) {
func TestStreamSetRow(t *testing.T) { func TestStreamSetRow(t *testing.T) {
// Test error exceptions // Test error exceptions
file := NewFile() file := NewFile()
defer func() {
assert.NoError(t, file.Close())
}()
streamWriter, err := file.NewStreamWriter("Sheet1") streamWriter, err := file.NewStreamWriter("Sheet1")
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualError(t, streamWriter.SetRow("A", []interface{}{}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error()) assert.EqualError(t, streamWriter.SetRow("A", []interface{}{}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
@ -233,6 +257,9 @@ func TestStreamSetRow(t *testing.T) {
func TestStreamSetRowNilValues(t *testing.T) { func TestStreamSetRowNilValues(t *testing.T) {
file := NewFile() file := NewFile()
defer func() {
assert.NoError(t, file.Close())
}()
streamWriter, err := file.NewStreamWriter("Sheet1") streamWriter, err := file.NewStreamWriter("Sheet1")
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, streamWriter.SetRow("A1", []interface{}{nil, nil, Cell{Value: "foo"}})) assert.NoError(t, streamWriter.SetRow("A1", []interface{}{nil, nil, Cell{Value: "foo"}}))
@ -244,6 +271,9 @@ func TestStreamSetRowNilValues(t *testing.T) {
func TestStreamSetRowWithStyle(t *testing.T) { func TestStreamSetRowWithStyle(t *testing.T) {
file := NewFile() file := NewFile()
defer func() {
assert.NoError(t, file.Close())
}()
zeroStyleID := 0 zeroStyleID := 0
grayStyleID, err := file.NewStyle(&Style{Font: &Font{Color: "#777777"}}) grayStyleID, err := file.NewStyle(&Style{Font: &Font{Color: "#777777"}})
assert.NoError(t, err) assert.NoError(t, err)
@ -273,6 +303,9 @@ func TestStreamSetRowWithStyle(t *testing.T) {
func TestStreamSetCellValFunc(t *testing.T) { func TestStreamSetCellValFunc(t *testing.T) {
f := NewFile() f := NewFile()
defer func() {
assert.NoError(t, f.Close())
}()
sw, err := f.NewStreamWriter("Sheet1") sw, err := f.NewStreamWriter("Sheet1")
assert.NoError(t, err) assert.NoError(t, err)
c := &xlsxC{} c := &xlsxC{}