forked from p30928647/excelize
Make the functions `SetSheetRow`, `New Style` and `SetCellStyle` concurrency safety
This commit is contained in:
parent
b7fece5173
commit
90d200a10b
20
cell.go
20
cell.go
|
@ -139,7 +139,9 @@ func (f *File) setCellTimeFunc(sheet, axis string, value time.Time) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
ws.Lock()
|
||||||
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
|
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
|
||||||
|
ws.Unlock()
|
||||||
|
|
||||||
var isNum bool
|
var isNum bool
|
||||||
cellData.T, cellData.V, isNum, err = setCellTime(value)
|
cellData.T, cellData.V, isNum, err = setCellTime(value)
|
||||||
|
@ -155,6 +157,8 @@ func (f *File) setCellTimeFunc(sheet, axis string, value time.Time) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setCellTime prepares cell type and Excel time by given Go time.Time type
|
||||||
|
// timestamp.
|
||||||
func setCellTime(value time.Time) (t string, b string, isNum bool, err error) {
|
func setCellTime(value time.Time) (t string, b string, isNum bool, err error) {
|
||||||
var excelTime float64
|
var excelTime float64
|
||||||
excelTime, err = timeToExcelTime(value)
|
excelTime, err = timeToExcelTime(value)
|
||||||
|
@ -170,6 +174,8 @@ func setCellTime(value time.Time) (t string, b string, isNum bool, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setCellDuration prepares cell type and value by given Go time.Duration type
|
||||||
|
// time duration.
|
||||||
func setCellDuration(value time.Duration) (t string, v string) {
|
func setCellDuration(value time.Duration) (t string, v string) {
|
||||||
v = strconv.FormatFloat(value.Seconds()/86400.0, 'f', -1, 32)
|
v = strconv.FormatFloat(value.Seconds()/86400.0, 'f', -1, 32)
|
||||||
return
|
return
|
||||||
|
@ -193,6 +199,8 @@ func (f *File) SetCellInt(sheet, axis string, value int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setCellInt prepares cell type and string type cell value by a given
|
||||||
|
// integer.
|
||||||
func setCellInt(value int) (t string, v string) {
|
func setCellInt(value int) (t string, v string) {
|
||||||
v = strconv.Itoa(value)
|
v = strconv.Itoa(value)
|
||||||
return
|
return
|
||||||
|
@ -209,11 +217,15 @@ func (f *File) SetCellBool(sheet, axis string, value bool) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
ws.Lock()
|
||||||
|
defer ws.Unlock()
|
||||||
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
|
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
|
||||||
cellData.T, cellData.V = setCellBool(value)
|
cellData.T, cellData.V = setCellBool(value)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setCellBool prepares cell type and string type cell value by a given
|
||||||
|
// boolean value.
|
||||||
func setCellBool(value bool) (t string, v string) {
|
func setCellBool(value bool) (t string, v string) {
|
||||||
t = "b"
|
t = "b"
|
||||||
if value {
|
if value {
|
||||||
|
@ -242,11 +254,15 @@ func (f *File) SetCellFloat(sheet, axis string, value float64, prec, bitSize int
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
ws.Lock()
|
||||||
|
defer ws.Unlock()
|
||||||
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
|
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
|
||||||
cellData.T, cellData.V = setCellFloat(value, prec, bitSize)
|
cellData.T, cellData.V = setCellFloat(value, prec, bitSize)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setCellFloat prepares cell type and string type cell value by a given
|
||||||
|
// float value.
|
||||||
func setCellFloat(value float64, prec, bitSize int) (t string, v string) {
|
func setCellFloat(value float64, prec, bitSize int) (t string, v string) {
|
||||||
v = strconv.FormatFloat(value, 'f', prec, bitSize)
|
v = strconv.FormatFloat(value, 'f', prec, bitSize)
|
||||||
return
|
return
|
||||||
|
@ -334,11 +350,15 @@ func (f *File) SetCellDefault(sheet, axis, value string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
ws.Lock()
|
||||||
|
defer ws.Unlock()
|
||||||
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
|
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
|
||||||
cellData.T, cellData.V = setCellDefault(value)
|
cellData.T, cellData.V = setCellDefault(value)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setCellDefault prepares cell type and string type cell value by a given
|
||||||
|
// string.
|
||||||
func setCellDefault(value string) (t string, v string) {
|
func setCellDefault(value string) (t string, v string) {
|
||||||
v = value
|
v = value
|
||||||
return
|
return
|
||||||
|
|
13
cell_test.go
13
cell_test.go
|
@ -25,8 +25,20 @@ func TestConcurrency(t *testing.T) {
|
||||||
// Concurrency set cell value
|
// Concurrency set cell value
|
||||||
assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("A%d", val), val))
|
assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("A%d", val), val))
|
||||||
assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("B%d", val), strconv.Itoa(val)))
|
assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("B%d", val), strconv.Itoa(val)))
|
||||||
|
// Concurrency get cell value
|
||||||
_, err := f.GetCellValue("Sheet1", fmt.Sprintf("A%d", val))
|
_, err := f.GetCellValue("Sheet1", fmt.Sprintf("A%d", val))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
// Concurrency set rows
|
||||||
|
assert.NoError(t, f.SetSheetRow("Sheet1", "B6", &[]interface{}{" Hello",
|
||||||
|
[]byte("World"), 42, int8(1<<8/2 - 1), int16(1<<16/2 - 1), int32(1<<32/2 - 1),
|
||||||
|
int64(1<<32/2 - 1), float32(42.65418), float64(-42.65418), float32(42), float64(42),
|
||||||
|
uint(1<<32 - 1), uint8(1<<8 - 1), uint16(1<<16 - 1), uint32(1<<32 - 1),
|
||||||
|
uint64(1<<32 - 1), true, complex64(5 + 10i)}))
|
||||||
|
// Concurrency create style
|
||||||
|
style, err := f.NewStyle(`{"font":{"color":"#1265BE","underline":"single"}}`)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// Concurrency set cell style
|
||||||
|
assert.NoError(t, f.SetCellStyle("Sheet1", "A3", "A3", style))
|
||||||
// Concurrency add picture
|
// Concurrency add picture
|
||||||
assert.NoError(t, f.AddPicture("Sheet1", "F21", filepath.Join("test", "images", "excel.jpg"),
|
assert.NoError(t, f.AddPicture("Sheet1", "F21", filepath.Join("test", "images", "excel.jpg"),
|
||||||
`{"x_offset": 10, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External", "positioning": "oneCell"}`))
|
`{"x_offset": 10, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External", "positioning": "oneCell"}`))
|
||||||
|
@ -59,6 +71,7 @@ func TestConcurrency(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, "1", val)
|
assert.Equal(t, "1", val)
|
||||||
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestConcurrency.xlsx")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckCellInArea(t *testing.T) {
|
func TestCheckCellInArea(t *testing.T) {
|
||||||
|
|
2
sheet.go
2
sheet.go
|
@ -1777,6 +1777,8 @@ func fillColumns(rowData *xlsxRow, col, row int) {
|
||||||
|
|
||||||
// makeContiguousColumns make columns in specific rows as contiguous.
|
// makeContiguousColumns make columns in specific rows as contiguous.
|
||||||
func makeContiguousColumns(ws *xlsxWorksheet, fromRow, toRow, colCount int) {
|
func makeContiguousColumns(ws *xlsxWorksheet, fromRow, toRow, colCount int) {
|
||||||
|
ws.Lock()
|
||||||
|
defer ws.Unlock()
|
||||||
for ; fromRow < toRow; fromRow++ {
|
for ; fromRow < toRow; fromRow++ {
|
||||||
rowData := &ws.SheetData.Row[fromRow-1]
|
rowData := &ws.SheetData.Row[fromRow-1]
|
||||||
fillColumns(rowData, colCount, fromRow)
|
fillColumns(rowData, colCount, fromRow)
|
||||||
|
|
|
@ -1990,6 +1990,8 @@ func (f *File) NewStyle(style interface{}) (int, error) {
|
||||||
fs.DecimalPlaces = 2
|
fs.DecimalPlaces = 2
|
||||||
}
|
}
|
||||||
s := f.stylesReader()
|
s := f.stylesReader()
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
// check given style already exist.
|
// check given style already exist.
|
||||||
if cellXfsID = f.getStyleID(s, fs); cellXfsID != -1 {
|
if cellXfsID = f.getStyleID(s, fs); cellXfsID != -1 {
|
||||||
return cellXfsID, err
|
return cellXfsID, err
|
||||||
|
@ -2693,7 +2695,8 @@ func (f *File) SetCellStyle(sheet, hcell, vcell string, styleID int) error {
|
||||||
}
|
}
|
||||||
prepareSheetXML(ws, vcol, vrow)
|
prepareSheetXML(ws, vcol, vrow)
|
||||||
makeContiguousColumns(ws, hrow, vrow, vcol)
|
makeContiguousColumns(ws, hrow, vrow, vcol)
|
||||||
|
ws.Lock()
|
||||||
|
defer ws.Unlock()
|
||||||
for r := hrowIdx; r <= vrowIdx; r++ {
|
for r := hrowIdx; r <= vrowIdx; r++ {
|
||||||
for k := hcolIdx; k <= vcolIdx; k++ {
|
for k := hcolIdx; k <= vcolIdx; k++ {
|
||||||
ws.SheetData.Row[r].C[k].S = styleID
|
ws.SheetData.Row[r].C[k].S = styleID
|
||||||
|
|
|
@ -11,10 +11,14 @@
|
||||||
|
|
||||||
package excelize
|
package excelize
|
||||||
|
|
||||||
import "encoding/xml"
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
// xlsxStyleSheet is the root element of the Styles part.
|
// xlsxStyleSheet is the root element of the Styles part.
|
||||||
type xlsxStyleSheet struct {
|
type xlsxStyleSheet struct {
|
||||||
|
sync.Mutex
|
||||||
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main styleSheet"`
|
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main styleSheet"`
|
||||||
NumFmts *xlsxNumFmts `xml:"numFmts,omitempty"`
|
NumFmts *xlsxNumFmts `xml:"numFmts,omitempty"`
|
||||||
Fonts *xlsxFonts `xml:"fonts,omitempty"`
|
Fonts *xlsxFonts `xml:"fonts,omitempty"`
|
||||||
|
|
Loading…
Reference in New Issue