Commit 11abbdeab9a30e15143603f3d17b656e8d2b578b
1 parent
1b1ad555
csv 读取加载
Showing
11 changed files
with
400 additions
and
5 deletions
Show diff stats
.gitignore
Makefile
... | ... | @@ -13,8 +13,9 @@ account: |
13 | 13 | game: |
14 | 14 | go run cmd/game.go |
15 | 15 | build: |
16 | - go build -o bin/account account.go | |
17 | - go build -o bin/game game.go | |
16 | + go build -o bin/account cmd/account.go | |
17 | + go build -o bin/game cmd/game.go | |
18 | + go build -o bin/test test/client.go | |
18 | 19 | |
19 | 20 | cert: |
20 | 21 | openssl req \ | ... | ... |
README.md
actions/accountaction.go renamed to actions/AccountAction.go
actions/roleaction.go renamed to actions/RoleAction.go
... | ... | @@ -8,6 +8,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF |
8 | 8 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
9 | 9 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= |
10 | 10 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= |
11 | +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= | |
12 | +github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg= | |
11 | 13 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
12 | 14 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= |
13 | 15 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= | ... | ... |
... | ... | @@ -0,0 +1,350 @@ |
1 | +package main | |
2 | + | |
3 | +import ( | |
4 | + "encoding/csv" | |
5 | + "fmt" | |
6 | + "github.com/axgle/mahonia" | |
7 | + "io" | |
8 | + "io/ioutil" | |
9 | + "log" | |
10 | + "os" | |
11 | + "path" | |
12 | + "pro2d/csvdata" | |
13 | + "reflect" | |
14 | + "strconv" | |
15 | + "strings" | |
16 | + "unicode" | |
17 | +) | |
18 | + | |
19 | +/** | |
20 | + * 将excel中的前四列转化为struct | |
21 | + * 第一列字段类型 如 int | |
22 | + * 第二列字段名称 如 显示顺序 | |
23 | + * 第三列字段名 如 id | |
24 | + * 第四列s,c,all s表示服务端使用 c表示客户端使用 all表示都使用 | |
25 | + */ | |
26 | + | |
27 | +var ( | |
28 | + lineNumber = 4 // 每个工作表至少需要读取的行数 | |
29 | + structBegin = "type %s struct {\n" // 结构体开始 | |
30 | + structValue = " %s %s `json:\"%s\" client:\"%s\"`" // 结构体的内容 | |
31 | + structValueForServer = " %s %s `json:\"%s\"`" // 服务端使用的结构体内容 | |
32 | + structRemarks = " // %s" // 结构体备注 | |
33 | + structValueEnd = "\n" // 结构体内容结束 | |
34 | + structEnd = "}\n" // 结构体结束 | |
35 | + header = "package %s\n\r" // 文件头 | |
36 | + | |
37 | + initpkg ="package csvdata\n\nimport \"sync\"\n\nvar CsvStruct map[string]interface{}\nvar CsvData *sync.Map\n\nfunc init() {\n\tCsvStruct = make(map[string]interface{})\n\tCsvData = new(sync.Map)\n\n\t%s\n}\n\nfunc GetCsv(key string) interface{}{\n\tif data, ok := CsvData.Load(key); ok {\n\t\treturn data\n\t}\n\treturn nil\n}\nfunc SetCsv(key, value interface{}) {\n\tCsvData.Store(key, value)\n}" | |
38 | + initline = "CsvStruct[\"%s\"] = %s{}\n" | |
39 | +) | |
40 | + | |
41 | +type Generate struct { | |
42 | + savePath string // 生成文件的保存路径 | |
43 | + data string // 生成文件的内容 | |
44 | + allType string // 文件当中的数据类型 | |
45 | +} | |
46 | + | |
47 | +func NewGenerate(savePath, allType string) *Generate { | |
48 | + return &Generate{ | |
49 | + savePath: savePath, | |
50 | + allType: allType, | |
51 | + } | |
52 | +} | |
53 | + | |
54 | +// GBK 转 UTF-8 | |
55 | +func GbkToUtf8(s string) string { | |
56 | + decoder := mahonia.NewDecoder("GBK") | |
57 | + return decoder.ConvertString(s) | |
58 | +} | |
59 | + | |
60 | +// UTF-8 转 GBK | |
61 | +func Utf8ToGbk(s string) string { | |
62 | + decoder := mahonia.NewDecoder("UTF-8") | |
63 | + return decoder.ConvertString(s) | |
64 | +} | |
65 | + | |
66 | +func GetGoTByCustomerT(t string) string { | |
67 | + switch t { | |
68 | + case "IntSlice": | |
69 | + return "[]int" | |
70 | + case "StringSlice": | |
71 | + return "[]string" | |
72 | + case "FloatSlice": | |
73 | + return "[]float32" | |
74 | + default: | |
75 | + return t | |
76 | + } | |
77 | +} | |
78 | + | |
79 | +func CustomerTypeToGo(allType string) map[string]bool { | |
80 | + s := strings.Split(allType, ",") | |
81 | + mt := make(map[string]bool) | |
82 | + for _, t := range s { | |
83 | + mt[GetGoTByCustomerT(t)] = true | |
84 | + } | |
85 | + return mt | |
86 | +} | |
87 | + | |
88 | +//csv to struct | |
89 | +func (g *Generate) CsvToStruct(csvpath, filename string) error { | |
90 | + csvfile, err := os.Open(csvpath+filename) | |
91 | + if err != nil { | |
92 | + return fmt.Errorf("ReadExcel|xlsx.OpenFile is err :%v", err) | |
93 | + } | |
94 | + defer csvfile.Close() | |
95 | + | |
96 | + r := csv.NewReader(csvfile) | |
97 | + i := 0 | |
98 | + sheetData := make([][]string, 0) | |
99 | + for { | |
100 | + if i >= lineNumber { | |
101 | + break | |
102 | + } | |
103 | + record, err := r.Read() | |
104 | + if err == io.EOF { | |
105 | + break | |
106 | + } | |
107 | + if err != nil { | |
108 | + log.Fatal(err) | |
109 | + } | |
110 | + i++ | |
111 | + sheetData = append(sheetData, record) | |
112 | + } | |
113 | + name := strings.Replace(filename, ".csv", "", -1) | |
114 | + data, err := g.SplicingData(sheetData, name) | |
115 | + if err != nil { | |
116 | + return fmt.Errorf("fileName:\"%v\" is err:%v", name, err) | |
117 | + } | |
118 | + | |
119 | + if data == "" { | |
120 | + return fmt.Errorf("ReadExcel|this.data is nil") | |
121 | + } | |
122 | + err = g.WriteNewFile(name, data) | |
123 | + if err != nil { | |
124 | + return err | |
125 | + } | |
126 | + | |
127 | + return nil | |
128 | +} | |
129 | + | |
130 | +//csv to mem | |
131 | +func (g *Generate)CsvToMem(csvpath, filename string) error { | |
132 | + csvfile, err := os.Open(csvpath+filename) | |
133 | + if err != nil { | |
134 | + return fmt.Errorf("ReadExcel|xlsx.OpenFile is err :%v", err) | |
135 | + } | |
136 | + defer csvfile.Close() | |
137 | + | |
138 | + r := csv.NewReader(csvfile) | |
139 | + i := 0 | |
140 | + sheetData := make([][]string, 0) | |
141 | + name := strings.Replace(filename, ".csv", "", -1) | |
142 | + for { | |
143 | + record, err := r.Read() | |
144 | + if err == io.EOF { | |
145 | + break | |
146 | + } | |
147 | + if err != nil { | |
148 | + log.Fatal(err) | |
149 | + } | |
150 | + | |
151 | + if i < lineNumber { | |
152 | + sheetData = append(sheetData, record) | |
153 | + }else { | |
154 | + //4行之后 | |
155 | + fields := sheetData[1] | |
156 | + typs := sheetData[2] //int, string | |
157 | + //keys := sheetData[3] //all, s, c | |
158 | + | |
159 | + t := reflect.ValueOf(csvdata.CsvStruct[name]).Type() | |
160 | + v := reflect.New(t).Elem() | |
161 | + for idx, field := range fields { | |
162 | + if field == "" || record[idx] == "" { | |
163 | + continue | |
164 | + } | |
165 | + | |
166 | + f := v.FieldByName(firstRuneToUpper(field)) | |
167 | + switch typs[idx] { | |
168 | + case "int": | |
169 | + id, err := strconv.Atoi(record[idx]) | |
170 | + if err != nil { | |
171 | + return err | |
172 | + } | |
173 | + f.SetInt(int64(id)) | |
174 | + case "string": | |
175 | + f.SetString(record[idx]) | |
176 | + } | |
177 | + | |
178 | + //fmt.Printf("%d, %s: %v, %v\n", idx, firstRuneToUpper(field), v.Field(idx), v.Interface()) | |
179 | + csvdata.SetCsv(name, v.Interface()) | |
180 | + } | |
181 | + } | |
182 | + i++ | |
183 | + } | |
184 | + return nil | |
185 | +} | |
186 | + | |
187 | +//拼装struct | |
188 | +func (g *Generate) SplicingData(data [][]string, structName string) (string, error) { | |
189 | + if len(data) != lineNumber { | |
190 | + return "", fmt.Errorf("SplicingData|sheetName:%v col's len:%d is err", data, len(data)) | |
191 | + } | |
192 | + marks := data[0] | |
193 | + fields := data[1] | |
194 | + typs := data[2] | |
195 | + keys := data[3] | |
196 | + structData := fmt.Sprintf(structBegin, firstRuneToUpper(structName)) | |
197 | + | |
198 | + for i, field := range fields { | |
199 | + err := g.CheckType(typs[i], structName) | |
200 | + if err != nil { | |
201 | + return "", err | |
202 | + } | |
203 | + switch keys[i] { | |
204 | + case "key","all": | |
205 | + structData += fmt.Sprintf(structValue, firstRuneToUpper(field), GetGoTByCustomerT(typs[i]), strings.ToLower(field), strings.ToLower(field)) | |
206 | + if field != "" { | |
207 | + structData += fmt.Sprintf(structRemarks, GbkToUtf8(marks[i])) | |
208 | + } | |
209 | + structData += fmt.Sprintf(structValueEnd) | |
210 | + case "s": | |
211 | + structData += fmt.Sprintf(structValueForServer, firstRuneToUpper(field), GetGoTByCustomerT(typs[i]), strings.ToLower(field)) | |
212 | + if field != "" { | |
213 | + structData += fmt.Sprintf(structRemarks,GbkToUtf8(marks[i])) | |
214 | + } | |
215 | + structData += fmt.Sprintf(structValueEnd) | |
216 | + case "c": | |
217 | + continue | |
218 | + default: | |
219 | + return "", fmt.Errorf("SplicingData|keys[%d]:\"%v\" is not in s,c,all", i, keys[i]) | |
220 | + } | |
221 | + } | |
222 | + structData += structEnd | |
223 | + return structData, nil | |
224 | +} | |
225 | + | |
226 | +// 拼装好的struct写入新的文件 | |
227 | +func (g *Generate) WriteNewFile(filename, data string) error { | |
228 | + str := strings.Split(g.savePath, "/") | |
229 | + if len(str) == 0 { | |
230 | + return fmt.Errorf("WriteNewFile|len(str) is 0") | |
231 | + } | |
232 | + | |
233 | + header = fmt.Sprintf(header, str[len(str)-1]) | |
234 | + data = header + data | |
235 | + | |
236 | + fw, err := os.OpenFile(g.savePath +"/" +filename+".go", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) | |
237 | + if err != nil { | |
238 | + return fmt.Errorf("WriteNewFile|OpenFile is err:%v", err) | |
239 | + } | |
240 | + defer fw.Close() | |
241 | + | |
242 | + _, err = fw.Write([]byte(data)) | |
243 | + if err != nil { | |
244 | + return fmt.Errorf("WriteNewFile|Write is err:%v", err) | |
245 | + } | |
246 | + | |
247 | + return nil | |
248 | +} | |
249 | + | |
250 | +// 拼装好的初始化写入init.go文件 | |
251 | +func (g *Generate) WriteInitPkg(data string) error { | |
252 | + str := strings.Split(g.savePath, "/") | |
253 | + if len(str) == 0 { | |
254 | + return fmt.Errorf("WriteNewFile|len(str) is 0") | |
255 | + } | |
256 | + | |
257 | + fw, err := os.OpenFile(g.savePath +"/init.go", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) | |
258 | + if err != nil { | |
259 | + return fmt.Errorf("WriteNewFile|OpenFile is err:%v", err) | |
260 | + } | |
261 | + defer fw.Close() | |
262 | + | |
263 | + _, err = fw.Write([]byte(fmt.Sprintf(initpkg, data))) | |
264 | + if err != nil { | |
265 | + return fmt.Errorf("WriteNewFile|Write is err:%v", err) | |
266 | + } | |
267 | + | |
268 | + return nil | |
269 | +} | |
270 | + | |
271 | +// 检测解析出来的字段类型是否符合要求 | |
272 | +func (g *Generate) CheckType(dataType, structName string) error { | |
273 | + res := strings.Index(g.allType, dataType) | |
274 | + if res == -1 { | |
275 | + return fmt.Errorf("CheckType|struct:\"%v\" dataType:\"%v\" is not in provide dataType", structName, dataType) | |
276 | + } | |
277 | + return nil | |
278 | +} | |
279 | + | |
280 | +// 字符串首字母转换成大写 | |
281 | +func firstRuneToUpper(str string) string { | |
282 | + data := []byte(str) | |
283 | + for k, v := range data { | |
284 | + if k == 0 { | |
285 | + first := []byte(strings.ToUpper(string(v))) | |
286 | + newData := data[1:] | |
287 | + data = append(first, newData...) | |
288 | + break | |
289 | + } | |
290 | + } | |
291 | + return string(data[:]) | |
292 | +} | |
293 | + | |
294 | +// 判断是否存在汉字或者是否为默认的工作表 | |
295 | +func hasChineseOrDefault(r string) bool { | |
296 | + if strings.Index(r, "Sheet") != -1 { | |
297 | + return true | |
298 | + } | |
299 | + for _, v := range []rune(r) { | |
300 | + if unicode.Is(unicode.Han, v) { | |
301 | + return true | |
302 | + } | |
303 | + } | |
304 | + return false | |
305 | +} | |
306 | + | |
307 | +// 读取Csv 转化为 struct | |
308 | +func (g *Generate) ReadCsvToStruct(readPath string) error { | |
309 | + files, err := ioutil.ReadDir(readPath) | |
310 | + if err != nil { | |
311 | + return fmt.Errorf("ReadExcel|ReadDir is err:%v", err) | |
312 | + } | |
313 | + | |
314 | + | |
315 | + data := "" | |
316 | + for _, file := range files { | |
317 | + if path.Ext(file.Name()) != ".csv" || hasChineseOrDefault(file.Name()) { | |
318 | + continue | |
319 | + } | |
320 | + err := g.CsvToStruct(readPath, file.Name()) | |
321 | + if err != nil { | |
322 | + return err | |
323 | + } | |
324 | + | |
325 | + name := strings.Replace(file.Name(), ".csv", "", -1) | |
326 | + data += fmt.Sprintf(initline, name, firstRuneToUpper(name)) | |
327 | + } | |
328 | + g.WriteInitPkg(data) | |
329 | + return nil | |
330 | +} | |
331 | + | |
332 | +// 读取Csv 转化为 memory数据 | |
333 | +func (g *Generate) ReadCsvToMemory(readPath string) error { | |
334 | + files, err := ioutil.ReadDir(readPath) | |
335 | + if err != nil { | |
336 | + return fmt.Errorf("ReadExcel|ReadDir is err:%v", err) | |
337 | + } | |
338 | + | |
339 | + for _, file := range files { | |
340 | + if path.Ext(file.Name()) != ".csv" || hasChineseOrDefault(file.Name()) { | |
341 | + continue | |
342 | + } | |
343 | + err := g.CsvToMem(readPath, file.Name()) | |
344 | + if err != nil { | |
345 | + return err | |
346 | + } | |
347 | + | |
348 | + } | |
349 | + return nil | |
350 | +} | ... | ... |
... | ... | @@ -0,0 +1,29 @@ |
1 | +package main | |
2 | + | |
3 | +import ( | |
4 | + "flag" | |
5 | + "fmt" | |
6 | + _ "pro2d/csvdata" | |
7 | +) | |
8 | + | |
9 | +var ( | |
10 | + savePath = flag.String("savePath", "/Users/mac/Documents/project/Pro2D/Pro2DServer/csvdata", "Path to save the makefile") | |
11 | + readPath = flag.String("readPath", "/Users/mac/Documents/project/Pro2D/Pro2DServer/tools/", "The path of reading Excel") | |
12 | + allType = flag.String("allType", "int, string", "Specified field type") | |
13 | +) | |
14 | + | |
15 | +func main() { | |
16 | + flag.Parse() | |
17 | + if *savePath == "" || *readPath == "" || *allType == "" { | |
18 | + fmt.Println("savePath, readPath or allType is nil") | |
19 | + return | |
20 | + } | |
21 | + | |
22 | + gt := NewGenerate(*savePath, *allType) | |
23 | + //err := gt.ReadCsvToStruct(*readPath) | |
24 | + err := gt.ReadCsvToMemory(*readPath) | |
25 | + if err != nil { | |
26 | + fmt.Printf("something err:%v\n", err) | |
27 | + return | |
28 | + } | |
29 | +} | |
0 | 30 | \ No newline at end of file | ... | ... |
utils/utils.go
... | ... | @@ -44,4 +44,13 @@ func FindIndex(schema interface{}) (string, []string){ |
44 | 44 | } |
45 | 45 | } |
46 | 46 | return strings.ToLower(s.Name()), index |
47 | +} | |
48 | + | |
49 | +func GetIdxBySlice(s []interface{}, i interface{}) (int){ | |
50 | + for idx, v := range s { | |
51 | + if v == i { | |
52 | + return idx | |
53 | + } | |
54 | + } | |
55 | + return -1 | |
47 | 56 | } |
48 | 57 | \ No newline at end of file | ... | ... |