summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cell.go20
-rw-r--r--cell_test.go13
-rw-r--r--sheet.go2
-rw-r--r--styles.go5
-rw-r--r--xmlStyles.go6
5 files changed, 44 insertions, 2 deletions
diff --git a/cell.go b/cell.go
index 1d08c8a..82e93c5 100644
--- a/cell.go
+++ b/cell.go
@@ -139,7 +139,9 @@ func (f *File) setCellTimeFunc(sheet, axis string, value time.Time) error {
if err != nil {
return err
}
+ ws.Lock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
+ ws.Unlock()
var isNum bool
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
}
+// 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) {
var excelTime float64
excelTime, err = timeToExcelTime(value)
@@ -170,6 +174,8 @@ func setCellTime(value time.Time) (t string, b string, isNum bool, err error) {
return
}
+// setCellDuration prepares cell type and value by given Go time.Duration type
+// time duration.
func setCellDuration(value time.Duration) (t string, v string) {
v = strconv.FormatFloat(value.Seconds()/86400.0, 'f', -1, 32)
return
@@ -193,6 +199,8 @@ func (f *File) SetCellInt(sheet, axis string, value int) error {
return err
}
+// setCellInt prepares cell type and string type cell value by a given
+// integer.
func setCellInt(value int) (t string, v string) {
v = strconv.Itoa(value)
return
@@ -209,11 +217,15 @@ func (f *File) SetCellBool(sheet, axis string, value bool) error {
if err != nil {
return err
}
+ ws.Lock()
+ defer ws.Unlock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.T, cellData.V = setCellBool(value)
return err
}
+// setCellBool prepares cell type and string type cell value by a given
+// boolean value.
func setCellBool(value bool) (t string, v string) {
t = "b"
if value {
@@ -242,11 +254,15 @@ func (f *File) SetCellFloat(sheet, axis string, value float64, prec, bitSize int
if err != nil {
return err
}
+ ws.Lock()
+ defer ws.Unlock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.T, cellData.V = setCellFloat(value, prec, bitSize)
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) {
v = strconv.FormatFloat(value, 'f', prec, bitSize)
return
@@ -334,11 +350,15 @@ func (f *File) SetCellDefault(sheet, axis, value string) error {
if err != nil {
return err
}
+ ws.Lock()
+ defer ws.Unlock()
cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.T, cellData.V = setCellDefault(value)
return err
}
+// setCellDefault prepares cell type and string type cell value by a given
+// string.
func setCellDefault(value string) (t string, v string) {
v = value
return
diff --git a/cell_test.go b/cell_test.go
index 91f4804..f11c708 100644
--- a/cell_test.go
+++ b/cell_test.go
@@ -25,8 +25,20 @@ func TestConcurrency(t *testing.T) {
// Concurrency set cell value
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)))
+ // Concurrency get cell value
_, err := f.GetCellValue("Sheet1", fmt.Sprintf("A%d", val))
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
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"}`))
@@ -59,6 +71,7 @@ func TestConcurrency(t *testing.T) {
t.Error(err)
}
assert.Equal(t, "1", val)
+ assert.NoError(t, f.SaveAs(filepath.Join("test", "TestConcurrency.xlsx")))
}
func TestCheckCellInArea(t *testing.T) {
diff --git a/sheet.go b/sheet.go
index 3a55540..8d3d457 100644
--- a/sheet.go
+++ b/sheet.go
@@ -1777,6 +1777,8 @@ func fillColumns(rowData *xlsxRow, col, row int) {
// makeContiguousColumns make columns in specific rows as contiguous.
func makeContiguousColumns(ws *xlsxWorksheet, fromRow, toRow, colCount int) {
+ ws.Lock()
+ defer ws.Unlock()
for ; fromRow < toRow; fromRow++ {
rowData := &ws.SheetData.Row[fromRow-1]
fillColumns(rowData, colCount, fromRow)
diff --git a/styles.go b/styles.go
index 235746c..5b9b200 100644
--- a/styles.go
+++ b/styles.go
@@ -1990,6 +1990,8 @@ func (f *File) NewStyle(style interface{}) (int, error) {
fs.DecimalPlaces = 2
}
s := f.stylesReader()
+ s.Lock()
+ defer s.Unlock()
// check given style already exist.
if cellXfsID = f.getStyleID(s, fs); cellXfsID != -1 {
return cellXfsID, err
@@ -2693,7 +2695,8 @@ func (f *File) SetCellStyle(sheet, hcell, vcell string, styleID int) error {
}
prepareSheetXML(ws, vcol, vrow)
makeContiguousColumns(ws, hrow, vrow, vcol)
-
+ ws.Lock()
+ defer ws.Unlock()
for r := hrowIdx; r <= vrowIdx; r++ {
for k := hcolIdx; k <= vcolIdx; k++ {
ws.SheetData.Row[r].C[k].S = styleID
diff --git a/xmlStyles.go b/xmlStyles.go
index 92e4e6a..afdc170 100644
--- a/xmlStyles.go
+++ b/xmlStyles.go
@@ -11,10 +11,14 @@
package excelize
-import "encoding/xml"
+import (
+ "encoding/xml"
+ "sync"
+)
// xlsxStyleSheet is the root element of the Styles part.
type xlsxStyleSheet struct {
+ sync.Mutex
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main styleSheet"`
NumFmts *xlsxNumFmts `xml:"numFmts,omitempty"`
Fonts *xlsxFonts `xml:"fonts,omitempty"`