Skip to content

Commit

Permalink
- Improved performance when reading large files, call Token to read t…
Browse files Browse the repository at this point in the history
…okens one by one instead Unmarshal. Related issue qax-os#20 ;

- Fix go test typo;
- Update README
  • Loading branch information
xuri committed Feb 12, 2017
1 parent 53564cb commit 0833a9d
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 28 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,18 @@ func main() {
}
// Insert a picture.
err = xlsx.AddPicture("Sheet1", "A2", "/tmp/image1.gif", 0, 0, 1, 1)
if err != nil {
fmt.Println(err)
}
// Insert a picture to sheet with scaling.
err = xlsx.AddPicture("Sheet1", "D2", "/tmp/image2.jpg", 0, 0, 0.5, 0.5)
if err != nil {
fmt.Println(err)
}
// Insert a picture offset in the cell.
err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.png", 15, 10, 1, 1)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Save the xlsx file with the origin path.
err = xlsx.Save()
Expand Down
24 changes: 24 additions & 0 deletions cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
xlsx = checkRow(xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand Down Expand Up @@ -143,6 +151,14 @@ func (f *File) SetCellHyperLink(sheet, axis, link string) {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
xlsx = checkRow(xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand Down Expand Up @@ -205,6 +221,14 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
xlsx = checkRow(xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
mergeCell := xlsxMergeCell{}
// Correct the coordinate area, such correct C1:B3 to B1:C3.
Expand Down
28 changes: 28 additions & 0 deletions excelize.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

// File define a populated XLSX file struct.
type File struct {
checked map[string]bool
XLSX map[string]string
Path string
SheetCount int
Expand All @@ -21,13 +22,15 @@ func OpenFile(filename string) (*File, error) {
var f *zip.ReadCloser
var err error
file := make(map[string]string)
c := make(map[string]bool)
sheetCount := 0
f, err = zip.OpenReader(filename)
if err != nil {
return &File{}, err
}
file, sheetCount, _ = ReadZip(f)
return &File{
checked: c,
XLSX: file,
Path: filename,
SheetCount: sheetCount,
Expand Down Expand Up @@ -66,6 +69,15 @@ func (f *File) SetCellInt(sheet string, axis string, value int) {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
xlsx = checkRow(xlsx)
f.checked[name] = true
}

if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand Down Expand Up @@ -98,6 +110,14 @@ func (f *File) SetCellStr(sheet string, axis string, value string) {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
xlsx = checkRow(xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand Down Expand Up @@ -133,6 +153,14 @@ func (f *File) SetCellDefault(sheet string, axis string, value string) {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
xlsx = checkRow(xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand Down
2 changes: 1 addition & 1 deletion excelize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func TestSetSheetBackground(t *testing.T) {
}
}

func TestSMergeCell(t *testing.T) {
func TestMergeCell(t *testing.T) {
xlsx, err := OpenFile("./test/Workbook1.xlsx")
if err != nil {
t.Log(err)
Expand Down
6 changes: 0 additions & 6 deletions lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package excelize
import (
"archive/zip"
"bytes"
"encoding/xml"
"io"
"log"
"math"
Expand All @@ -26,11 +25,6 @@ func ReadZipReader(r *zip.Reader) (map[string]string, int, error) {
fileList[v.Name] = readFile(v)
if len(v.Name) > 18 {
if v.Name[0:19] == "xl/worksheets/sheet" {
var xlsx xlsxWorksheet
xml.Unmarshal([]byte(fileList[v.Name]), &xlsx)
xlsx = checkRow(xlsx)
output, _ := xml.Marshal(xlsx)
fileList[v.Name] = replaceWorkSheetsRelationshipsNameSpace(string(output))
worksheets++
}
}
Expand Down
7 changes: 6 additions & 1 deletion picture.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,18 @@ import (
// xlsx := excelize.CreateFile()
// // Insert a picture.
// err := xlsx.AddPicture("Sheet1", "A2", "/tmp/image1.jpg", 0, 0, 1, 1)
// if err != nil {
// fmt.Println(err)
// }
// // Insert a picture to sheet with scaling.
// err = xlsx.AddPicture("Sheet1", "D2", "/tmp/image1.png", 0, 0, 0.5, 0.5)
// if err != nil {
// fmt.Println(err)
// }
// // Insert a picture offset in the cell.
// err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.gif", 15, 10, 1, 1)
// if err != nil {
// fmt.Println(err)
// os.Exit(1)
// }
// err = xlsx.WriteTo("/tmp/Workbook.xlsx")
// if err != nil {
Expand Down
48 changes: 29 additions & 19 deletions rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,37 @@ import (
// }
//
func (f *File) GetRows(sheet string) [][]string {
xlsx := xlsxWorksheet{}
r := [][]string{}
rows := [][]string{}
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
err := xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
decoder := xml.NewDecoder(strings.NewReader(f.readXML(name)))
d, err := readXMLSST(f)
if err != nil {
return r
return rows
}
rows := xlsx.SheetData.Row
for _, row := range rows {
c := []string{}
for _, colCell := range row.C {
val, _ := colCell.getValueFrom(f)
c = append(c, val)
var inElement string
var row []string
for {
token, _ := decoder.Token()
if token == nil {
break
}
switch startElement := token.(type) {
case xml.StartElement:
inElement = startElement.Name.Local
if inElement == "row" {
var r xlsxRow
decoder.DecodeElement(&r, &startElement)
for _, colCell := range r.C {
val, _ := colCell.getValueFrom(f, d)
row = append(row, val)
}
rows = append(rows, row)
row = row[:0]
}
default:
}
r = append(r, c)
}
return r
return rows
}

// SetRowHeight provides a function to set the height of a single row.
Expand Down Expand Up @@ -65,23 +79,19 @@ func (f *File) SetRowHeight(sheet string, rowIndex int, height float64) {
}

// readXMLSST read xmlSST simple function.
func readXMLSST(f *File) (xlsxSST, error) {
func readXMLSST(f *File) (*xlsxSST, error) {
shardStrings := xlsxSST{}
err := xml.Unmarshal([]byte(f.readXML("xl/sharedStrings.xml")), &shardStrings)
return shardStrings, err
return &shardStrings, err
}

// getValueFrom return a value from a column/row cell, this function is inteded
// to be used with for range on rows an argument with the xlsx opened file.
func (xlsx *xlsxC) getValueFrom(f *File) (string, error) {
func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
switch xlsx.T {
case "s":
xlsxSI := 0
xlsxSI, _ = strconv.Atoi(xlsx.V)
d, err := readXMLSST(f)
if err != nil {
return "", err
}
if len(d.SI[xlsxSI].R) > 0 {
value := ""
for _, v := range d.SI[xlsxSI].R {
Expand Down

0 comments on commit 0833a9d

Please sign in to comment.