f_xlsx 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +38 -0
- data/LICENSE.txt +21 -0
- data/Makefile +32 -0
- data/README.md +51 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/excel.dylib +0 -0
- data/ext/excel.h +107 -0
- data/ext/excel.so +0 -0
- data/ext/go.mod +19 -0
- data/ext/go.sum +69 -0
- data/ext/types.h +23 -0
- data/ext/xlsx.go +299 -0
- data/f_xlsx.gemspec +43 -0
- data/lib/f_xlsx/base_types.rb +63 -0
- data/lib/f_xlsx/file.rb +180 -0
- data/lib/f_xlsx/lib_c.rb +20 -0
- data/lib/f_xlsx/version.rb +3 -0
- data/lib/f_xlsx/xlsx_ext.rb +44 -0
- data/lib/f_xlsx.rb +17 -0
- data/test.rb +22 -0
- metadata +134 -0
data/ext/xlsx.go
ADDED
@@ -0,0 +1,299 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"fmt"
|
5
|
+
"sync"
|
6
|
+
"unsafe"
|
7
|
+
|
8
|
+
"github.com/google/uuid"
|
9
|
+
"github.com/xuri/excelize/v2"
|
10
|
+
)
|
11
|
+
|
12
|
+
/*
|
13
|
+
#include <stdlib.h>
|
14
|
+
#include <types.h>
|
15
|
+
*/
|
16
|
+
import "C"
|
17
|
+
|
18
|
+
var files map[uint32]*excelize.File
|
19
|
+
var once sync.Once
|
20
|
+
|
21
|
+
func getFile(uid uint32) *excelize.File {
|
22
|
+
return files[uid]
|
23
|
+
}
|
24
|
+
|
25
|
+
func setFile(uid uint32, file *excelize.File) {
|
26
|
+
once.Do(func() {
|
27
|
+
files = make(map[uint32]*excelize.File)
|
28
|
+
})
|
29
|
+
files[uid] = file
|
30
|
+
}
|
31
|
+
|
32
|
+
//export printStr
|
33
|
+
func printStr(str *C.char) {
|
34
|
+
ss := C.GoString(str)
|
35
|
+
fmt.Println(ss)
|
36
|
+
}
|
37
|
+
|
38
|
+
//export newFile
|
39
|
+
func newFile() uint32 {
|
40
|
+
file := excelize.NewFile()
|
41
|
+
uid := fuuid()
|
42
|
+
setFile(uid, file)
|
43
|
+
return uid
|
44
|
+
}
|
45
|
+
|
46
|
+
//export openFile
|
47
|
+
func openFile(filePath *C.char) uint32 {
|
48
|
+
path := C.GoString(filePath)
|
49
|
+
fmt.Println(path)
|
50
|
+
file, err := excelize.OpenFile(path)
|
51
|
+
if err != nil {
|
52
|
+
fmt.Println(err)
|
53
|
+
return 0
|
54
|
+
}
|
55
|
+
uid := fuuid()
|
56
|
+
setFile(uid, file)
|
57
|
+
return uid
|
58
|
+
}
|
59
|
+
|
60
|
+
//export newSheet
|
61
|
+
func newSheet(fileId uint32, sheetNamcC *C.char) C.int {
|
62
|
+
f := getFile(fileId)
|
63
|
+
sheetName := C.GoString(sheetNamcC)
|
64
|
+
num, _ := f.NewSheet(sheetName)
|
65
|
+
return C.int(num)
|
66
|
+
}
|
67
|
+
|
68
|
+
//export setSheetName
|
69
|
+
func setSheetName(fileId uint32, sheetNameC *C.char, targetSheetNameC *C.char) {
|
70
|
+
f := getFile(fileId)
|
71
|
+
sheetName := C.GoString(sheetNameC)
|
72
|
+
targetSheetName := C.GoString(targetSheetNameC)
|
73
|
+
f.SetSheetName(sheetName, targetSheetName)
|
74
|
+
}
|
75
|
+
|
76
|
+
//export getSheetList
|
77
|
+
func getSheetList(fileId uint32) *C.struct_str_arr {
|
78
|
+
f := getFile(fileId)
|
79
|
+
names := f.GetSheetList()
|
80
|
+
return fromGo2Arrs(names)
|
81
|
+
}
|
82
|
+
|
83
|
+
//export getSheetName
|
84
|
+
func getSheetName(fileId uint32, index int) *C.char {
|
85
|
+
f := getFile(fileId)
|
86
|
+
name := f.GetSheetName(index)
|
87
|
+
rtn := C.CString(name)
|
88
|
+
// defer C.free(unsafe.Pointer(rtn))
|
89
|
+
return rtn
|
90
|
+
}
|
91
|
+
|
92
|
+
//export closeFile
|
93
|
+
func closeFile(fileId uint32) {
|
94
|
+
f := getFile(fileId)
|
95
|
+
f.Close()
|
96
|
+
delete(files, fileId)
|
97
|
+
}
|
98
|
+
|
99
|
+
//export setSheetVisible
|
100
|
+
func setSheetVisible(fileId uint32, sheetNameC *C.char, visible C.int) {
|
101
|
+
f := getFile(fileId)
|
102
|
+
sheetName := C.GoString(sheetNameC)
|
103
|
+
f.SetSheetVisible(sheetName, int(visible) == 1)
|
104
|
+
}
|
105
|
+
|
106
|
+
//export getSheetVisible
|
107
|
+
func getSheetVisible(fileId uint32, sheetNameC *C.char) C.int {
|
108
|
+
f := getFile(fileId)
|
109
|
+
sheetName := C.GoString(sheetNameC)
|
110
|
+
vis, _ := f.GetSheetVisible(sheetName)
|
111
|
+
if vis {
|
112
|
+
return C.int(1)
|
113
|
+
}
|
114
|
+
return C.int(0)
|
115
|
+
}
|
116
|
+
|
117
|
+
//export deleteSheet
|
118
|
+
func deleteSheet(fileId uint32, sheetNameC *C.char) {
|
119
|
+
f := getFile(fileId)
|
120
|
+
sheetName := C.GoString(sheetNameC)
|
121
|
+
f.DeleteSheet(sheetName)
|
122
|
+
}
|
123
|
+
|
124
|
+
//export setCellValue
|
125
|
+
func setCellValue(fileId uint32, sheetNameC *C.char, row C.int, col C.int, value unsafe.Pointer, typ int) {
|
126
|
+
f := getFile(fileId)
|
127
|
+
sheetName := C.GoString(sheetNameC)
|
128
|
+
cell, _ := excelize.CoordinatesToCellName(int(col)+1, int(row)+1)
|
129
|
+
switch int(typ) {
|
130
|
+
case 1: //int
|
131
|
+
ptr := (*C.int)(value)
|
132
|
+
f.SetCellInt(sheetName, cell, int(*ptr))
|
133
|
+
case 2: //float
|
134
|
+
ptr := (*C.float)(value)
|
135
|
+
f.SetCellFloat(sheetName, cell, float64(*ptr), 4, 32)
|
136
|
+
case 3: //string
|
137
|
+
val := (*C.char)(value)
|
138
|
+
f.SetCellStr(sheetName, cell, C.GoString(val))
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
//export getCellValue
|
143
|
+
func getCellValue(fileId uint32, sheetNameC *C.char, row C.int, col C.int) *C.char {
|
144
|
+
f := getFile(fileId)
|
145
|
+
sheetName := C.GoString(sheetNameC)
|
146
|
+
cell, _ := excelize.CoordinatesToCellName(int(col)+1, int(row)+1)
|
147
|
+
val, _ := f.GetCellValue(sheetName, cell)
|
148
|
+
|
149
|
+
str := C.CString(val)
|
150
|
+
// defer C.free(unsafe.Pointer(str))
|
151
|
+
return str
|
152
|
+
}
|
153
|
+
|
154
|
+
//export getRows
|
155
|
+
func getRows(fileId uint32, sheetNameC *C.char) *C.struct_str_arr2 {
|
156
|
+
f := getFile(fileId)
|
157
|
+
sheetName := C.GoString(sheetNameC)
|
158
|
+
rows, _ := f.GetRows(sheetName)
|
159
|
+
return fromGo2Arrs2(rows)
|
160
|
+
}
|
161
|
+
|
162
|
+
//export putRows
|
163
|
+
func putRows(fileId uint32, sheetNameC *C.char, rowsC *C.struct_str_arr2) {
|
164
|
+
f := getFile(fileId)
|
165
|
+
sheetName := C.GoString(sheetNameC)
|
166
|
+
vRows := (*[2 << 32]*C.struct_str_arr)(unsafe.Pointer(rowsC.arr))
|
167
|
+
for i := 0; i < int(rowsC.s_size); i++ {
|
168
|
+
row := fromArr2Go(vRows[i])
|
169
|
+
innerPutRow(f, sheetName, i, row)
|
170
|
+
}
|
171
|
+
|
172
|
+
}
|
173
|
+
|
174
|
+
//export putRow
|
175
|
+
func putRow(fileId uint32, sheetNameC *C.char, rowIndex int, rowC *C.struct_str_arr) {
|
176
|
+
f := getFile(fileId)
|
177
|
+
sheetName := C.GoString(sheetNameC)
|
178
|
+
row := fromArr2Go(rowC)
|
179
|
+
fmt.Printf("%v\n", len(row))
|
180
|
+
innerPutRow(f, sheetName, rowIndex, row)
|
181
|
+
}
|
182
|
+
|
183
|
+
func innerPutRow(f *excelize.File, sheetName string, rowIndex int, row []string) {
|
184
|
+
for i := 0; i < len(row); i++ {
|
185
|
+
cell, _ := excelize.CoordinatesToCellName(i+1, rowIndex+1)
|
186
|
+
f.SetCellStr(sheetName, cell, row[i])
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
//export mergeCell
|
191
|
+
func mergeCell(fileId uint32, sheetNameC *C.char, startRow int, startCol int, endRow int, endCol int) {
|
192
|
+
f := getFile(fileId)
|
193
|
+
sheetName := C.GoString(sheetNameC)
|
194
|
+
cellStart, _ := excelize.CoordinatesToCellName(int(startCol)+1, int(startRow)+1)
|
195
|
+
cellEnd, _ := excelize.CoordinatesToCellName(int(endCol)+1, int(endRow)+1)
|
196
|
+
f.MergeCell(sheetName, cellStart, cellEnd)
|
197
|
+
}
|
198
|
+
|
199
|
+
//export unMergeCell
|
200
|
+
func unMergeCell(fileId uint32, sheetNameC *C.char, startRow int, startCol int, endRow int, endCol int) {
|
201
|
+
f := getFile(fileId)
|
202
|
+
sheetName := C.GoString(sheetNameC)
|
203
|
+
cellStart, _ := excelize.CoordinatesToCellName(int(startCol)+1, int(startRow)+1)
|
204
|
+
cellEnd, _ := excelize.CoordinatesToCellName(int(endCol)+1, int(endRow)+1)
|
205
|
+
f.UnmergeCell(sheetName, cellStart, cellEnd)
|
206
|
+
}
|
207
|
+
|
208
|
+
//export getMergeCells
|
209
|
+
func getMergeCells(fileId uint32, sheetNameC *C.char) *C.merge_cell_arr {
|
210
|
+
f := getFile(fileId)
|
211
|
+
sheetName := C.GoString(sheetNameC)
|
212
|
+
cells, _ := f.GetMergeCells(sheetName)
|
213
|
+
return fromGoCells2C(cells)
|
214
|
+
}
|
215
|
+
|
216
|
+
//export save
|
217
|
+
func save(fileId uint32) {
|
218
|
+
f := getFile(fileId)
|
219
|
+
f.Save()
|
220
|
+
f.Close()
|
221
|
+
delete(files, fileId)
|
222
|
+
}
|
223
|
+
|
224
|
+
//export saveAs
|
225
|
+
func saveAs(fileId uint32, path *C.char) {
|
226
|
+
f := getFile(fileId)
|
227
|
+
strPath := C.GoString(path)
|
228
|
+
f.SaveAs(strPath)
|
229
|
+
f.Close()
|
230
|
+
delete(files, fileId)
|
231
|
+
}
|
232
|
+
|
233
|
+
func fromGo2Arrs(strs []string) *C.struct_str_arr {
|
234
|
+
var arr = (*C.struct_str_arr)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_str_arr{}))))
|
235
|
+
arr.s_size = C.int(len(strs))
|
236
|
+
|
237
|
+
var ss = C.malloc(C.size_t(arr.s_size) * C.size_t(unsafe.Sizeof(uintptr(0))))
|
238
|
+
|
239
|
+
var arrSs = (*[2 << 32]*C.char)(unsafe.Pointer(ss))
|
240
|
+
for i, s := range strs {
|
241
|
+
arrSs[i] = C.CString(s)
|
242
|
+
}
|
243
|
+
arr.arr = (**C.char)(ss)
|
244
|
+
return arr
|
245
|
+
}
|
246
|
+
|
247
|
+
func fromGo2Arrs2(strs [][]string) *C.struct_str_arr2 {
|
248
|
+
var arr2 = (*C.struct_str_arr2)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_str_arr2{}))))
|
249
|
+
arr2.s_size = C.int(len(strs))
|
250
|
+
var ss = C.malloc(C.size_t(arr2.s_size) * C.size_t(unsafe.Sizeof(uintptr(0))))
|
251
|
+
var arrSs = (*[2 << 32]*C.struct_str_arr)(unsafe.Pointer(ss))
|
252
|
+
|
253
|
+
for i, _strs := range strs {
|
254
|
+
arrSs[i] = fromGo2Arrs(_strs)
|
255
|
+
}
|
256
|
+
arr2.arr = (**C.struct_str_arr)(ss)
|
257
|
+
return arr2
|
258
|
+
}
|
259
|
+
|
260
|
+
func fromArr2Go(rowC *C.struct_str_arr) []string {
|
261
|
+
vRow := (*[2 << 32]*C.char)(unsafe.Pointer(rowC.arr))
|
262
|
+
row := make([]string, 0, int(rowC.s_size))
|
263
|
+
for ii := 0; ii < int(rowC.s_size); ii++ {
|
264
|
+
row = append(row, C.GoString(vRow[ii]))
|
265
|
+
}
|
266
|
+
return row
|
267
|
+
}
|
268
|
+
|
269
|
+
func fromGoCells2C(cells []excelize.MergeCell) *C.merge_cell_arr {
|
270
|
+
var cCells = (**C.merge_cell)(C.malloc(C.size_t(len(cells)) * C.size_t(unsafe.Sizeof(C.merge_cell{}))))
|
271
|
+
var cellArr = (*C.merge_cell_arr)(C.malloc(C.size_t(unsafe.Sizeof(C.merge_cell_arr{}))))
|
272
|
+
cellArr.s_size = C.int(len(cells))
|
273
|
+
cellArr.cells = cCells
|
274
|
+
var arrCells = (*[2 << 32]*C.merge_cell)(unsafe.Pointer(cCells))
|
275
|
+
for i := 0; i < len(cells); i++ {
|
276
|
+
c := cells[i]
|
277
|
+
mc := (*C.merge_cell)(C.malloc(C.size_t(unsafe.Sizeof(C.merge_cell{}))))
|
278
|
+
startA := c.GetStartAxis()
|
279
|
+
startCol, startRow, _ := excelize.CellNameToCoordinates(startA)
|
280
|
+
endA := c.GetEndAxis()
|
281
|
+
endCol, endRow, _ := excelize.CellNameToCoordinates(endA)
|
282
|
+
cellValue := c.GetCellValue()
|
283
|
+
fmt.Println(cellValue)
|
284
|
+
mc.val = C.CString(cellValue)
|
285
|
+
mc.start_row = C.int(startRow) - 1
|
286
|
+
mc.start_col = C.int(startCol) - 1
|
287
|
+
mc.end_row = C.int(endRow) - 1
|
288
|
+
mc.end_col = C.int(endCol) - 1
|
289
|
+
arrCells[i] = mc
|
290
|
+
}
|
291
|
+
return cellArr
|
292
|
+
}
|
293
|
+
|
294
|
+
func fuuid() uint32 {
|
295
|
+
return uuid.New().ID()
|
296
|
+
}
|
297
|
+
|
298
|
+
func main() {
|
299
|
+
}
|
data/f_xlsx.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "f_xlsx/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "f_xlsx"
|
8
|
+
spec.version = FXlsx::VERSION
|
9
|
+
spec.authors = ["dong.wang"]
|
10
|
+
spec.email = ["dong.wang@rccchina.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{cgo support xlsx, from golang excelize}
|
13
|
+
spec.description = %q{cgo support xlsx, from golang excelize}
|
14
|
+
spec.homepage = "https://github.com/secondrocker/f_xlsx"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
21
|
+
|
22
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
23
|
+
spec.metadata["source_code_uri"] = "https://github.com/secondrocker/f_xlsx"
|
24
|
+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
25
|
+
else
|
26
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
27
|
+
"public gem pushes."
|
28
|
+
end
|
29
|
+
|
30
|
+
# Specify which files should be added to the gem when it is released.
|
31
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
32
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
33
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
34
|
+
end
|
35
|
+
spec.bindir = "exe"
|
36
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
37
|
+
spec.require_paths = ["lib"]
|
38
|
+
|
39
|
+
spec.add_development_dependency "bundler", '>= 1.0', '<= 3.0'
|
40
|
+
spec.add_development_dependency "rake", '~> 13.0'
|
41
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
42
|
+
spec.add_dependency "ffi", "~> 1"
|
43
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module FXlsx
|
2
|
+
class CStrArray < FFI::Struct
|
3
|
+
layout :arr, :pointer,
|
4
|
+
:s_size, :int
|
5
|
+
|
6
|
+
def value
|
7
|
+
str = []
|
8
|
+
self[:arr].read_array_of_pointer(self[:s_size]).map do |str_ptr|
|
9
|
+
str << str_ptr.read_string
|
10
|
+
LibC.free(str_ptr)
|
11
|
+
end
|
12
|
+
LibC.free(self[:arr])
|
13
|
+
LibC.free(self)
|
14
|
+
str
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class CStrArray2 < FFI::Struct
|
19
|
+
layout :arr, :pointer,
|
20
|
+
:s_size, :int
|
21
|
+
def value
|
22
|
+
rows = []
|
23
|
+
self[:arr].read_array_of_pointer(self[:s_size]).each do |p|
|
24
|
+
# CStrArray value方法自动释放指针,本处不需释放
|
25
|
+
rows << CStrArray.new(p).value
|
26
|
+
end
|
27
|
+
LibC.free(self[:arr])
|
28
|
+
LibC.free(self)
|
29
|
+
rows
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class CCell < FFI::Struct
|
34
|
+
layout :start_row, :int,
|
35
|
+
:start_col, :int,
|
36
|
+
:end_row, :int,
|
37
|
+
:end_col, :int,
|
38
|
+
:val, :string
|
39
|
+
end
|
40
|
+
|
41
|
+
class CCellArray < FFI::Struct
|
42
|
+
layout :cells, :pointer,
|
43
|
+
:s_size, :int
|
44
|
+
|
45
|
+
def values
|
46
|
+
_cells = []
|
47
|
+
self[:cells].read_array_of_pointer(self[:s_size]).each do |cell_ptr|
|
48
|
+
c = CCell.new(cell_ptr)
|
49
|
+
_cells << {
|
50
|
+
start_row: c[:start_row],
|
51
|
+
start_col: c[:start_col],
|
52
|
+
end_row: c[:end_row],
|
53
|
+
end_col: c[:end_col],
|
54
|
+
value: c[:val]
|
55
|
+
}
|
56
|
+
LibC.free(cell_ptr)
|
57
|
+
end
|
58
|
+
LibC.free(self[:cells])
|
59
|
+
LibC.free(self)
|
60
|
+
_cells
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/f_xlsx/file.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
module FXlsx
|
2
|
+
class File
|
3
|
+
attr_accessor :id, :closed, :has_file
|
4
|
+
|
5
|
+
def self.new_file
|
6
|
+
XlsxExt.load_lib
|
7
|
+
instance = File.new
|
8
|
+
instance.id = XlsxExt.newFile()
|
9
|
+
instance
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.open_file(path)
|
13
|
+
XlsxExt.load_lib
|
14
|
+
instance = File.new
|
15
|
+
instance.id = XlsxExt.openFile(path)
|
16
|
+
instance.has_file = true
|
17
|
+
instance
|
18
|
+
end
|
19
|
+
|
20
|
+
def closed?
|
21
|
+
closed
|
22
|
+
end
|
23
|
+
|
24
|
+
def new_sheet(sheet_name)
|
25
|
+
raise "file closed" if self.closed?
|
26
|
+
|
27
|
+
XlsxExt.newSheet(self.id, sheet_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_sheet_name(sheet_name, target_sheet_name)
|
31
|
+
raise "file closed" if self.closed?
|
32
|
+
|
33
|
+
XlsxExt.setSheetName(self.id, sheet_name, target_sheet_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_sheet_visible(sheet_name, visible)
|
37
|
+
raise "file closed" if self.closed?
|
38
|
+
|
39
|
+
XlsxExt.setSheetVisible(self.id, sheet_name, visible ? 1 : 0)
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_sheet_visible(sheet_name)
|
43
|
+
raise "file closed" if self.closed?
|
44
|
+
|
45
|
+
XlsxExt.getSheetVisible(self.id, sheet_name) == 1
|
46
|
+
end
|
47
|
+
|
48
|
+
def delete_sheet(sheet_name)
|
49
|
+
raise "file closed" if self.closed?
|
50
|
+
|
51
|
+
XlsxExt.deleteSheet(self.id, sheet_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_sheet_list
|
55
|
+
raise "file closed" if self.closed?
|
56
|
+
|
57
|
+
ptr = XlsxExt.getSheetList(self.id)
|
58
|
+
ptr.value
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_sheet_name(index)
|
62
|
+
raise "file closed" if self.closed?
|
63
|
+
|
64
|
+
XlsxExt.getSheetName(self.id, index)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def set_cell_value(sheet_name, row, col, value)
|
69
|
+
raise "file closed" if self.closed?
|
70
|
+
|
71
|
+
value = '' if value.nil?
|
72
|
+
ptr = nil
|
73
|
+
typ = if value.is_a?(Integer)
|
74
|
+
ptr = FFI::MemoryPointer.new(:int)
|
75
|
+
ptr.write_int(value)
|
76
|
+
1
|
77
|
+
elsif value.is_a?(Float)
|
78
|
+
ptr = FFI::MemoryPointer.new(:float)
|
79
|
+
ptr.write_float(value)
|
80
|
+
2
|
81
|
+
else
|
82
|
+
ptr = FFI::MemoryPointer.from_string(value.to_s)
|
83
|
+
3
|
84
|
+
end
|
85
|
+
XlsxExt.setCellValue(self.id, sheet_name, row, col, ptr, typ)
|
86
|
+
ptr.free if ptr
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_cell_value(sheet_name, row, col)
|
90
|
+
raise "file closed" if self.closed?
|
91
|
+
|
92
|
+
XlsxExt.getCellValue(self.id, sheet_name, row, col)
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_rows(sheet_name)
|
96
|
+
raise "file closed" if self.closed?
|
97
|
+
|
98
|
+
XlsxExt.getRows(self.id, sheet_name).value
|
99
|
+
end
|
100
|
+
|
101
|
+
def put_row(sheet_name, row_index, row)
|
102
|
+
raise "file closed" if self.closed?
|
103
|
+
|
104
|
+
# 不需要手动释放
|
105
|
+
str = CStrArray.new
|
106
|
+
str[:s_size] = row.size
|
107
|
+
ptr = FFI::MemoryPointer.new(:pointer, row.size)
|
108
|
+
pps = row.map{|x| FFI::MemoryPointer.from_string(x.to_s) }
|
109
|
+
ptr.write_array_of_pointer(pps)
|
110
|
+
str[:arr] = ptr
|
111
|
+
XlsxExt.putRow(self.id, sheet_name, row_index,str)
|
112
|
+
pps.each(&:free)
|
113
|
+
ptr.free
|
114
|
+
end
|
115
|
+
|
116
|
+
def put_rows(sheet_name, rows)
|
117
|
+
raise "file closed" if self.closed?
|
118
|
+
#不需要手动释放
|
119
|
+
str2 = CStrArray2.new
|
120
|
+
str2[:s_size] = rows.size
|
121
|
+
ptr2 = FFI::MemoryPointer.new(:pointer, rows.size)
|
122
|
+
todoRelease = [ptr2]
|
123
|
+
|
124
|
+
ptr2_arr = rows.map do |row|
|
125
|
+
# 不需要手动释放
|
126
|
+
str = CStrArray.new
|
127
|
+
str[:s_size] = row.size
|
128
|
+
|
129
|
+
ptr = FFI::MemoryPointer.new(:pointer, row.size)
|
130
|
+
todoRelease << ptr
|
131
|
+
sptrs = row.map{|s| FFI::MemoryPointer.from_string(s.to_s)}
|
132
|
+
todoRelease += sptrs
|
133
|
+
ptr.write_array_of_pointer(sptrs)
|
134
|
+
str[:arr] = ptr
|
135
|
+
str.pointer
|
136
|
+
end
|
137
|
+
todoRelease += ptr2_arr
|
138
|
+
ptr2.write_array_of_pointer(ptr2_arr)
|
139
|
+
str2[:arr] = ptr2
|
140
|
+
XlsxExt.putRows(self.id, sheet_name, str2)
|
141
|
+
todoRelease.each(&:free)
|
142
|
+
end
|
143
|
+
|
144
|
+
def merge_cell(sheet_name, start_row, start_col, end_row, end_col)
|
145
|
+
raise "file closed" if self.closed?
|
146
|
+
|
147
|
+
XlsxExt.mergeCell(self.id, sheet_name, start_row, start_col, end_row, end_col)
|
148
|
+
end
|
149
|
+
|
150
|
+
def unmerge_cell(sheet_name, start_row, start_col, end_row, end_col)
|
151
|
+
raise "file closed" if self.closed?
|
152
|
+
|
153
|
+
XlsxExt.unMergeCell(self.id, sheet_name, start_row, start_col, end_row, end_col)
|
154
|
+
end
|
155
|
+
|
156
|
+
def get_merge_cells(sheet_name)
|
157
|
+
raise "file closed" if self.closed?
|
158
|
+
XlsxExt.getMergeCells(self.id, sheet_name).values
|
159
|
+
end
|
160
|
+
|
161
|
+
def save
|
162
|
+
raise "file closed" if self.closed?
|
163
|
+
raise "new file can't save, call save_as" unless has_file
|
164
|
+
XlsxExt.save(self.id)
|
165
|
+
self.closed = true
|
166
|
+
end
|
167
|
+
|
168
|
+
def save_as(path)
|
169
|
+
raise "file closed" if self.closed?
|
170
|
+
XlsxExt.saveAs(self.id,path)
|
171
|
+
self.closed = true
|
172
|
+
end
|
173
|
+
|
174
|
+
def close
|
175
|
+
raise "file closed" if self.closed?
|
176
|
+
XlsxExt.closeFile(self.id)
|
177
|
+
self.closed = true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
data/lib/f_xlsx/lib_c.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module FXlsx
|
4
|
+
module LibC
|
5
|
+
extend FFI::Library
|
6
|
+
ffi_lib FFI::Library::LIBC
|
7
|
+
|
8
|
+
# memory allocators
|
9
|
+
attach_function :malloc, [:size_t], :pointer
|
10
|
+
attach_function :calloc, [:size_t], :pointer
|
11
|
+
attach_function :valloc, [:size_t], :pointer
|
12
|
+
attach_function :realloc, [:pointer, :size_t], :pointer
|
13
|
+
attach_function :free, [:pointer], :void
|
14
|
+
|
15
|
+
# memory movers
|
16
|
+
attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
|
17
|
+
attach_function :bcopy, [:pointer, :pointer, :size_t], :void
|
18
|
+
|
19
|
+
end # module LibC
|
20
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
LIB_PATH = File.expand_path("../../../ext/excel.#{FFI::Platform::LIBSUFFIX}", __FILE__)
|
2
|
+
module FXlsx
|
3
|
+
module XlsxExt
|
4
|
+
|
5
|
+
def self.load_lib
|
6
|
+
return if @lib_loaded
|
7
|
+
@lib_loaded = true
|
8
|
+
extend FFI::Library
|
9
|
+
ffi_lib LIB_PATH
|
10
|
+
attach_function :printStr, [:string], :void
|
11
|
+
|
12
|
+
attach_function :newFile, [], :uint32
|
13
|
+
attach_function :openFile, [:string], :uint32
|
14
|
+
|
15
|
+
attach_function :newSheet, [:uint32, :string], :int
|
16
|
+
attach_function :deleteSheet, [:uint32, :string], :void
|
17
|
+
attach_function :setSheetName, [:uint32, :string, :string], :void
|
18
|
+
attach_function :setSheetVisible, [:uint32, :string, :int], :void
|
19
|
+
attach_function :getSheetVisible, [:uint32, :string], :int
|
20
|
+
|
21
|
+
attach_function :getSheetList, [:uint32], CStrArray.ptr
|
22
|
+
attach_function :getSheetName, [:uint32, :int], :string
|
23
|
+
|
24
|
+
attach_function :setCellValue, [:uint32, :string, :int, :int, :pointer, :int], :void
|
25
|
+
attach_function :getCellValue, [:uint32, :string, :int, :int], :string
|
26
|
+
|
27
|
+
attach_function :getRows, [:uint32, :string], CStrArray2.ptr
|
28
|
+
|
29
|
+
attach_function :putRow, [:uint32, :string, :int, CStrArray.ptr], :void
|
30
|
+
attach_function :putRows, [:uint32, :string, CStrArray2.ptr], :void
|
31
|
+
|
32
|
+
|
33
|
+
attach_function :mergeCell, [:uint32, :string, :int, :int, :int, :int], :void
|
34
|
+
attach_function :unMergeCell, [:uint32, :string, :int, :int, :int, :int], :void
|
35
|
+
|
36
|
+
attach_function :getMergeCells, [:uint32, :string], CCellArray.ptr
|
37
|
+
|
38
|
+
attach_function :save, [:uint32], :void
|
39
|
+
attach_function :saveAs, [:uint32, :string], :void
|
40
|
+
|
41
|
+
attach_function :closeFile, [:uint32], :void
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/f_xlsx.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "f_xlsx/version"
|
2
|
+
require "f_xlsx/lib_c"
|
3
|
+
require "f_xlsx/base_types"
|
4
|
+
require "f_xlsx/xlsx_ext"
|
5
|
+
require "f_xlsx/file"
|
6
|
+
|
7
|
+
module FXlsx
|
8
|
+
|
9
|
+
def self.new_file
|
10
|
+
File.new_file
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.open_file(path)
|
14
|
+
File.open_file(path)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/test.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'f_xlsx'
|
2
|
+
stop = false
|
3
|
+
fork do
|
4
|
+
File.open("test.pid","w"){ |f| f.puts(Process.pid)}
|
5
|
+
trap('INT') do
|
6
|
+
puts 'will stop'
|
7
|
+
stop = true
|
8
|
+
end
|
9
|
+
while true do
|
10
|
+
# path2 = "/Users/wangdong/Desktop/3620230626131231产品录入模板.xlsx"
|
11
|
+
path2 = "/Users/wangdong/Desktop/批量搜索产品清单.xlsx"
|
12
|
+
f2 = FXlsx.open_file(path2)
|
13
|
+
# f2.put_row('Sheet1',5,[5,'b','c'])
|
14
|
+
# f2.put_rows('Sheet1',[[2,nil],[1,'b','c']])
|
15
|
+
pp f2.get_merge_cells('使用说明')
|
16
|
+
|
17
|
+
f2.unmerge_cell('使用说明', 0,0, 48, 44)
|
18
|
+
f2.close
|
19
|
+
# f2.save_as(path2)
|
20
|
+
break if stop
|
21
|
+
end
|
22
|
+
end
|