Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xuri
excelize
提交
5221729b
excelize
项目概览
xuri
/
excelize
通知
13
Star
2
Fork
4
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
excelize
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
已验证
提交
5221729b
编写于
6月 22, 2020
作者:
xurime
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
make columns iterator read cell streamingly and add max column limit on ColumnNumberToName
上级
dcb772d6
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
106 addition
and
76 deletion
+106
-76
cell.go
cell.go
+0
-3
col.go
col.go
+63
-57
col_test.go
col_test.go
+40
-13
lib.go
lib.go
+3
-0
rows.go
rows.go
+0
-3
未找到文件。
cell.go
浏览文件 @
5221729b
...
...
@@ -41,9 +41,6 @@ var rwMutex sync.RWMutex
func
(
f
*
File
)
GetCellValue
(
sheet
,
axis
string
)
(
string
,
error
)
{
return
f
.
getCellStringFunc
(
sheet
,
axis
,
func
(
x
*
xlsxWorksheet
,
c
*
xlsxC
)
(
string
,
bool
,
error
)
{
val
,
err
:=
c
.
getValueFrom
(
f
,
f
.
sharedStringsReader
())
if
err
!=
nil
{
return
val
,
false
,
err
}
return
val
,
true
,
err
})
}
...
...
col.go
浏览文件 @
5221729b
...
...
@@ -13,8 +13,8 @@ import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"math"
"strconv"
"strings"
"github.com/mohae/deepcopy"
...
...
@@ -34,10 +34,11 @@ type Cols struct {
sheet
string
cols
[]
xlsxCols
f
*
File
decoder
*
xml
.
Decoder
sheetXML
[]
byte
}
// GetCols return all the columns in a sheet by given worksheet name (case sensitive). For example:
// GetCols return all the columns in a sheet by given worksheet name (case
// sensitive). For example:
//
// cols, err := f.Cols("Sheet1")
// if err != nil {
...
...
@@ -60,29 +61,17 @@ func (f *File) GetCols(sheet string) ([][]string, error) {
if
err
!=
nil
{
return
nil
,
err
}
results
:=
make
([][]
string
,
0
,
64
)
for
cols
.
Next
()
{
if
cols
.
Error
()
!=
nil
{
break
}
col
,
err
:=
cols
.
Rows
()
if
err
!=
nil
{
break
}
col
,
_
:=
cols
.
Rows
()
results
=
append
(
results
,
col
)
}
return
results
,
nil
}
// Next will return true if the next col element is found.
func
(
cols
*
Cols
)
Next
()
bool
{
cols
.
curCol
++
return
cols
.
curCol
<=
cols
.
totalCol
}
...
...
@@ -91,27 +80,53 @@ func (cols *Cols) Error() error {
return
cols
.
err
}
// Rows return the current column's row values
// Rows return the current column's row values
.
func
(
cols
*
Cols
)
Rows
()
([]
string
,
error
)
{
var
(
err
error
rows
[]
string
err
error
inElement
string
cellCol
,
cellRow
int
rows
[]
string
)
if
cols
.
stashCol
>=
cols
.
curCol
{
return
rows
,
err
}
for
i
:=
1
;
i
<=
cols
.
totalRow
;
i
++
{
colName
,
_
:=
ColumnNumberToName
(
cols
.
curCol
)
val
,
_
:=
cols
.
f
.
GetCellValue
(
cols
.
sheet
,
fmt
.
Sprintf
(
"%s%d"
,
colName
,
i
))
rows
=
append
(
rows
,
val
)
d
:=
cols
.
f
.
sharedStringsReader
()
decoder
:=
cols
.
f
.
xmlNewDecoder
(
bytes
.
NewReader
(
cols
.
sheetXML
))
for
{
token
,
_
:=
decoder
.
Token
()
if
token
==
nil
{
break
}
switch
startElement
:=
token
.
(
type
)
{
case
xml
.
StartElement
:
inElement
=
startElement
.
Name
.
Local
if
inElement
==
"c"
{
for
_
,
attr
:=
range
startElement
.
Attr
{
if
attr
.
Name
.
Local
==
"r"
{
if
cellCol
,
cellRow
,
err
=
CellNameToCoordinates
(
attr
.
Value
);
err
!=
nil
{
return
rows
,
err
}
blank
:=
cellRow
-
len
(
rows
)
for
i
:=
1
;
i
<
blank
;
i
++
{
rows
=
append
(
rows
,
""
)
}
if
cellCol
==
cols
.
curCol
{
colCell
:=
xlsxC
{}
_
=
decoder
.
DecodeElement
(
&
colCell
,
&
startElement
)
val
,
_
:=
colCell
.
getValueFrom
(
cols
.
f
,
d
)
rows
=
append
(
rows
,
val
)
}
}
}
}
}
}
return
rows
,
nil
}
// Cols returns a columns iterator, used for streaming/reading data for a worksheet with a large data. For example:
// Cols returns a columns iterator, used for streaming/reading data for a
// worksheet with a large data. For example:
//
// cols, err := f.Cols("Sheet1")
// if err != nil {
...
...
@@ -134,60 +149,51 @@ func (f *File) Cols(sheet string) (*Cols, error) {
if
!
ok
{
return
nil
,
ErrSheetNotExist
{
sheet
}
}
if
f
.
Sheet
[
name
]
!=
nil
{
output
,
_
:=
xml
.
Marshal
(
f
.
Sheet
[
name
])
f
.
saveFileList
(
name
,
replaceRelationshipsNameSpaceBytes
(
output
))
}
var
(
inElement
string
cols
Cols
colsNum
,
rowsNum
[]
int
inElement
string
cols
Cols
cellCol
int
err
error
)
decoder
:=
f
.
xmlNewDecoder
(
bytes
.
NewReader
(
f
.
readXML
(
name
))
)
cols
.
sheetXML
=
f
.
readXML
(
name
)
decoder
:=
f
.
xmlNewDecoder
(
bytes
.
NewReader
(
cols
.
sheetXML
))
for
{
token
,
_
:=
decoder
.
Token
()
if
token
==
nil
{
break
}
switch
startElement
:=
token
.
(
type
)
{
case
xml
.
StartElement
:
inElement
=
startElement
.
Name
.
Local
if
inElement
==
"dimension"
{
colsNum
=
make
([]
int
,
0
)
rowsNum
=
make
([]
int
,
0
)
if
inElement
==
"row"
{
for
_
,
attr
:=
range
startElement
.
Attr
{
if
attr
.
Name
.
Local
==
"ref"
{
sheetCoordinates
:=
attr
.
Value
if
i
:=
strings
.
Index
(
sheetCoordinates
,
":"
);
i
<=
-
1
{
return
&
cols
,
errors
.
New
(
"Sheet coordinates are wrong"
)
if
attr
.
Name
.
Local
==
"r"
{
if
cols
.
totalRow
,
err
=
strconv
.
Atoi
(
attr
.
Value
);
err
!=
nil
{
return
&
cols
,
err
}
coordinates
:=
strings
.
Split
(
sheetCoordinates
,
":"
)
for
_
,
coordinate
:=
range
coordinates
{
c
,
r
,
_
:=
SplitCellName
(
coordinate
)
columnNum
,
_
:=
ColumnNameToNumber
(
c
)
colsNum
=
append
(
colsNum
,
columnNum
)
rowsNum
=
append
(
rowsNum
,
r
)
}
}
}
if
inElement
==
"c"
{
for
_
,
attr
:=
range
startElement
.
Attr
{
if
attr
.
Name
.
Local
==
"r"
{
if
cellCol
,
_
,
err
=
CellNameToCoordinates
(
attr
.
Value
);
err
!=
nil
{
return
&
cols
,
err
}
if
cellCol
>
cols
.
totalCol
{
cols
.
totalCol
=
cellCol
}
}
}
cols
.
totalCol
=
colsNum
[
1
]
-
(
colsNum
[
0
]
-
1
)
cols
.
totalRow
=
rowsNum
[
1
]
-
(
rowsNum
[
0
]
-
1
)
}
default
:
}
}
cols
.
f
=
f
cols
.
sheet
=
trimSheetName
(
sheet
)
cols
.
decoder
=
f
.
xmlNewDecoder
(
bytes
.
NewReader
(
f
.
readXML
(
name
)))
return
&
cols
,
nil
}
...
...
col_test.go
浏览文件 @
5221729b
package
excelize
import
(
"bytes"
"path/filepath"
"testing"
...
...
@@ -61,7 +60,7 @@ func TestCols(t *testing.T) {
func
TestColumnsIterator
(
t
*
testing
.
T
)
{
const
(
sheet2
=
"Sheet2"
expectedNumCol
=
4
expectedNumCol
=
9
)
f
,
err
:=
OpenFile
(
filepath
.
Join
(
"test"
,
"Book1.xlsx"
))
...
...
@@ -82,29 +81,57 @@ func TestColumnsIterator(t *testing.T) {
for
_
,
cell
:=
range
cells
{
assert
.
NoError
(
t
,
f
.
SetCellValue
(
"Sheet1"
,
cell
,
1
))
}
f
.
Sheet
[
"xl/worksheets/sheet1.xml"
]
=
&
xlsxWorksheet
{
Dimension
:
&
xlsxDimension
{
Ref
:
"C2:D4"
,
},
}
cols
,
err
=
f
.
Cols
(
"Sheet1"
)
require
.
NoError
(
t
,
err
)
colCount
=
0
for
cols
.
Next
()
{
colCount
++
require
.
True
(
t
,
colCount
<=
2
,
"colCount is greater than expected"
)
require
.
True
(
t
,
colCount
<=
4
,
"colCount is greater than expected"
)
}
assert
.
Equal
(
t
,
2
,
colCount
)
assert
.
Equal
(
t
,
4
,
colCount
)
}
func
TestColsError
(
t
*
testing
.
T
)
{
xlsx
,
err
:=
OpenFile
(
filepath
.
Join
(
"test"
,
"Book1.xlsx"
))
f
,
err
:=
OpenFile
(
filepath
.
Join
(
"test"
,
"Book1.xlsx"
))
if
!
assert
.
NoError
(
t
,
err
)
{
t
.
FailNow
()
}
_
,
err
=
f
.
Cols
(
"SheetN"
)
assert
.
EqualError
(
t
,
err
,
"sheet SheetN is not exist"
)
}
func
TestGetColsError
(
t
*
testing
.
T
)
{
f
,
err
:=
OpenFile
(
filepath
.
Join
(
"test"
,
"Book1.xlsx"
))
if
!
assert
.
NoError
(
t
,
err
)
{
t
.
FailNow
()
}
_
,
err
=
xlsx
.
Cols
(
"SheetN"
)
_
,
err
=
f
.
Get
Cols
(
"SheetN"
)
assert
.
EqualError
(
t
,
err
,
"sheet SheetN is not exist"
)
f
=
NewFile
()
delete
(
f
.
Sheet
,
"xl/worksheets/sheet1.xml"
)
f
.
XLSX
[
"xl/worksheets/sheet1.xml"
]
=
[]
byte
(
`<worksheet><sheetData><row r="A"><c r="2" t="str"><v>B</v></c></row></sheetData></worksheet>`
)
f
.
checked
=
nil
_
,
err
=
f
.
GetCols
(
"Sheet1"
)
assert
.
EqualError
(
t
,
err
,
`strconv.Atoi: parsing "A": invalid syntax`
)
f
=
NewFile
()
delete
(
f
.
Sheet
,
"xl/worksheets/sheet1.xml"
)
f
.
XLSX
[
"xl/worksheets/sheet1.xml"
]
=
[]
byte
(
`<worksheet><sheetData><row r="2"><c r="A" t="str"><v>B</v></c></row></sheetData></worksheet>`
)
f
.
checked
=
nil
_
,
err
=
f
.
GetCols
(
"Sheet1"
)
assert
.
EqualError
(
t
,
err
,
`cannot convert cell "A" to coordinates: invalid cell name "A"`
)
f
=
NewFile
()
cols
,
err
:=
f
.
Cols
(
"Sheet1"
)
assert
.
NoError
(
t
,
err
)
cols
.
totalRow
=
2
cols
.
totalCol
=
2
cols
.
curCol
=
1
cols
.
decoder
=
[]
byte
(
`<worksheet><sheetData><row r="1"><c r="A" t="str"><v>A</v></c></row></sheetData></worksheet>`
)
_
,
err
=
cols
.
Rows
()
assert
.
EqualError
(
t
,
err
,
`cannot convert cell "A" to coordinates: invalid cell name "A"`
)
}
func
TestColsRows
(
t
*
testing
.
T
)
{
...
...
@@ -112,7 +139,7 @@ func TestColsRows(t *testing.T) {
f
.
NewSheet
(
"Sheet1"
)
cols
,
err
:=
f
.
Cols
(
"Sheet1"
)
assert
.
EqualError
(
t
,
err
,
`Sheet coordinates are wrong`
)
assert
.
NoError
(
t
,
err
)
assert
.
NoError
(
t
,
f
.
SetCellValue
(
"Sheet1"
,
"A1"
,
1
))
f
.
Sheet
[
"xl/worksheets/sheet1.xml"
]
=
&
xlsxWorksheet
{
...
...
@@ -126,7 +153,7 @@ func TestColsRows(t *testing.T) {
assert
.
NoError
(
t
,
err
)
// Test if token is nil
cols
.
decoder
=
f
.
xmlNewDecoder
(
bytes
.
NewReader
(
nil
))
cols
.
decoder
=
nil
_
,
err
=
cols
.
Rows
()
assert
.
NoError
(
t
,
err
)
}
...
...
lib.go
浏览文件 @
5221729b
...
...
@@ -152,6 +152,9 @@ func ColumnNumberToName(num int) (string, error) {
if
num
<
1
{
return
""
,
fmt
.
Errorf
(
"incorrect column number %d"
,
num
)
}
if
num
>
TotalColumns
{
return
""
,
fmt
.
Errorf
(
"column number exceeds maximum limit"
)
}
var
col
string
for
num
>
0
{
col
=
string
((
num
-
1
)
%
26
+
65
)
+
col
...
...
rows.go
浏览文件 @
5221729b
...
...
@@ -46,9 +46,6 @@ func (f *File) GetRows(sheet string) ([][]string, error) {
}
results
:=
make
([][]
string
,
0
,
64
)
for
rows
.
Next
()
{
if
rows
.
Error
()
!=
nil
{
break
}
row
,
err
:=
rows
.
Columns
()
if
err
!=
nil
{
break
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录