From e9d6617baa67400e53e9745cf94f0614154089a5 Mon Sep 17 00:00:00 2001 From: lj-wsdj <1134294381@qq.com> Date: Thu, 20 Jun 2024 15:33:14 +0800 Subject: [PATCH] add import --- README.md | 9 ++- import1_test.go | 31 +++++++++++ imports/xlsx.go | 142 ++++++++++++++++++++++++++++++++++++++++++++++++ test7.xlsx | Bin 0 -> 9002 bytes 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 import1_test.go create mode 100644 imports/xlsx.go create mode 100644 test7.xlsx diff --git a/README.md b/README.md index aacbf41..76dcdb3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # xlsx -excel的导出导入(目前仅完成导出) +excel的导出和导入 ## 导出功能 如果要使用导出,则传入的数据必须为指针,类型可以是struct或者元素为struct的slice。 @@ -9,3 +9,10 @@ excel的导出导入(目前仅完成导出) 当导出的excel表格列数不确定时,tag使用`export:"loop:true"`,这样会将所有字段导出到excel表格中。 详情请看测试文件 + +## 导入功能 +如果要使用导入,则传入的数据必须为指针,类型是元素为struct的slice。 + +通过tag来确认需要导入的字段,内容为`import:"index:1"`,index为excel表格中的列数,从1开始。当需要导入的数据为日期时,结构体中必须为time.Time类型,不可以用自定义的日期类型,且excel表格中的日期格式必须为yyyy-mm-dd或yyyy-mm-dd hh:mm:ss。 + +详细请看测试文件 diff --git a/import1_test.go b/import1_test.go new file mode 100644 index 0000000..da53e93 --- /dev/null +++ b/import1_test.go @@ -0,0 +1,31 @@ +package xlsx + +import ( + "fmt" + "testing" + "time" + + "git.botann.com/lijun/xlsx/imports" +) + +type Data struct { + Autoseq int + Name string `import:"true,index:1"` + Unit string `import:"true,index:2"` + TestCol string + Invest int64 `import:"true,index:3"` + CreateTime time.Time `import:"true,index:4"` +} + +func TestMain(t *testing.T) { + var data []Data + importer, err := imports.NewFileImporter("./test7.xlsx", &data) + if err != nil { + fmt.Println(err) + } + err = importer.Import(0) + if err != nil { + fmt.Println(err) + } + fmt.Println(data) +} diff --git a/imports/xlsx.go b/imports/xlsx.go new file mode 100644 index 0000000..9d8d29f --- /dev/null +++ b/imports/xlsx.go @@ -0,0 +1,142 @@ +package imports + +import ( + "fmt" + "io" + "reflect" + "strconv" + "strings" + "time" + + "github.com/xuri/excelize/v2" +) + +type Importer struct { + Reader io.Reader + Sheets []string + xlsxFile *excelize.File + Data interface{} +} + +func NewFileImporter(file string, data any) (*Importer, error) { + f, err := excelize.OpenFile(file) + if err != nil { + return nil, err + } + sheets := f.GetSheetList() + return &Importer{ + xlsxFile: f, + Sheets: sheets, + Data: data, + }, nil +} + +func NewFileReaderImporter(reader io.Reader, data any) (*Importer, error) { + f, err := excelize.OpenReader(reader) + if err != nil { + return nil, err + } + sheets := f.GetSheetList() + return &Importer{ + xlsxFile: f, + Sheets: sheets, + Data: data, + }, nil +} + +func (i *Importer) Import(sheetIndex int) error { + v := reflect.ValueOf(i.Data) + if v.Kind() != reflect.Pointer { + return fmt.Errorf("data must be pointer") + } + switch v.Elem().Kind() { + case reflect.Slice: + return i.dealFile(sheetIndex) + default: + return fmt.Errorf("data must be slice") + } +} + +func (i *Importer) dealFile(sheetIndex int) error { + sheet := i.Sheets[sheetIndex] + rows, err := i.xlsxFile.Rows(sheet) + if err != nil { + return err + } + vdata := reflect.ValueOf(i.Data).Elem() + if vdata.Type().Elem().Kind() != reflect.Struct { + return fmt.Errorf("element must be struct") + } + testData := reflect.New(vdata.Type().Elem()) + tempDic := make(map[int]string) + for i := 0; i < testData.Elem().NumField(); i++ { + t := testData.Elem().Type().Field(i) + tag, ok := t.Tag.Lookup("import") + if ok { + tagMap := dealTag(tag) + index, _ := strconv.Atoi(tagMap["index"]) + tempDic[index] = t.Name + } + } + rowIndex := 0 + for rows.Next() { + rowIndex += 1 + // 第一行为表头 + if rowIndex > 1 { + row, err := rows.Columns() + if err != nil { + return err + } + newData := reflect.New(vdata.Type().Elem()) + for colIndex := range row { + colIndex += 1 + cellName, _ := excelize.CoordinatesToCellName(colIndex, rowIndex) + value, _ := i.xlsxFile.GetCellValue(sheet, cellName) + if fieldName, ok := tempDic[colIndex]; ok { + field := newData.Elem().FieldByName(fieldName) + switch field.Kind() { + case reflect.String: + field.SetString(value) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + intValue, _ := strconv.Atoi(value) + field.SetInt(int64(intValue)) + case reflect.Float32, reflect.Float64: + floatValue, _ := strconv.ParseFloat(value, 64) + field.SetFloat(floatValue) + case reflect.Bool: + boolValue, _ := strconv.ParseBool(value) + field.SetBool(boolValue) + // 如果是结构体,只支持时间类型,并且结构体的字段类型必须是time.Time,不能为自定的时间类型,并且excel里面的时间格式必须是yyyy-mm-dd或者yyyy-mm-dd hh:mm:ss + case reflect.Struct: + t := time.Time{} + if strings.Contains(value, ":") { + t, _ = time.Parse(time.DateTime, value) + } else { + t, _ = time.Parse(time.DateOnly, value) + } + field.Set(reflect.ValueOf(t)) + } + } + } + vdata.Set(reflect.Append(vdata, newData.Elem())) + } + } + if err = rows.Close(); err != nil { + return err + } + return nil +} + +func dealTag(tag string) map[string]string { + tag_list := strings.Split(tag, ",") + tag_map := make(map[string]string) + for _, tag := range tag_list { + tag_kv := strings.Split(tag, ":") + if len(tag_kv) != 2 { + continue + } + tag_map[tag_kv[0]] = tag_kv[1] + } + return tag_map +} diff --git a/test7.xlsx b/test7.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f4d9aea3ec0af11debd668a7e340b4ac0cec9565 GIT binary patch literal 9002 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 S+^iVje_z0Z