golang使用json格式實(shí)現(xiàn)增刪查改的實(shí)現(xiàn)示例
需求和思路
在一般的小項(xiàng)目或者一個(gè)小軟件,例如客戶端之類的小程序中,可能會(huì)需要數(shù)據(jù)的持久化.但是使用一般的數(shù)據(jù)庫(kù)(Mysql)之類的不合適.使用sqlite3這種嵌入式的是個(gè)較好的方法,但是Go語(yǔ)言中sqlite3的庫(kù)是C語(yǔ)言的,Cgo不支持跨平臺(tái)編譯.正是由于這種需求,才想到使用json格式將數(shù)據(jù)直接保存在文件中.具體的思路是怎么樣呢? 在Go語(yǔ)言中如果要將數(shù)據(jù)轉(zhuǎn)化成json格式的話,有兩種格式 struct 和 map. 如果同時(shí)需要增刪查改功能的話,將map作為中間格式是比較合適的.接下來(lái)我們就來(lái)實(shí)現(xiàn)它.
查詢操作
這種操作的實(shí)現(xiàn)比較簡(jiǎn)單,直接將文件中的數(shù)據(jù)讀取出來(lái),使用json庫(kù)反序列化就可以了. 代碼如下 :
type Product struct { Name string `json:'name'` Num int `json:'num'`}func findAll() { ps := make([]Product, 0) data, err := ioutil.ReadFile('./index.json') if err != nil { log.Fatal(err) } // 這里參數(shù)要指定為變量的地址 err = json.Unmarshal(data, &ps) if err != nil { log.Fatal(err) } fmt.Println(ps)}
添加操作
添加的實(shí)現(xiàn)實(shí)在查詢的基礎(chǔ)上的,我們需要先查詢文件中的數(shù)據(jù)庫(kù),并轉(zhuǎn)化為map格式,再將struct也轉(zhuǎn)化為map格式(這里要使用反射),合并map,json序列化,最后保存在文件中.代碼如下:
func create() { fields := make([]map[string]interface{}, 0) p1 := &Product{ Name: 'Blog', Num: 2, } _, _ = json.Marshal(p1) // 讀取文件中的數(shù)據(jù),保存為map格式 data, _ := ioutil.ReadFile('./index.json') err := json.Unmarshal(data, &fields) if err != nil { log.Fatal(err) } // 使用反射將struct轉(zhuǎn)化為map tp := reflect.TypeOf(p1).Elem() vp := reflect.ValueOf(p1).Elem() field := make(map[string]interface{}, 0) for i := 0; i < tp.NumField(); i++ { field1 := tp.Field(i) field2 := vp.Field(i) key := field1.Tag.Get('json') field[key] = field2.Interface() } // 合并map fields = append(fields, field) // 寫入文件 out, _ := json.Marshal(fields) _ = ioutil.WriteFile('./index.json', out, 0755)}
條件查詢
思路: 將struct轉(zhuǎn)化為map,根據(jù)輸入的條件查詢.查詢的結(jié)果轉(zhuǎn)化為struct.代碼如下:
func FindOne() { product := &Product{} p1 := &Product{ Name: 'John', Num: 23, } // 使用反射將struct轉(zhuǎn)化為map tp := reflect.TypeOf(p1).Elem() vp := reflect.ValueOf(p1).Elem() field := make(map[string]interface{}, 0) for i := 0; i < tp.NumField(); i++ { field1 := tp.Field(i) field2 := vp.Field(i) key := field1.Tag.Get('json') switch field2.Kind() { case reflect.Int: field[key] = float64(field2.Interface().(int)) case reflect.Int8: field[key] = float64(field2.Interface().(int8)) case reflect.Int16: field[key] = float64(field2.Interface().(int16)) case reflect.Int32: field[key] = float64(field2.Interface().(int32)) case reflect.Int64: field[key] = float64(field2.Interface().(int64)) case reflect.Uint: field[key] = float64(field2.Interface().(uint)) case reflect.Uint8: field[key] = float64(field2.Interface().(uint8)) case reflect.Uint16: field[key] = float64(field2.Interface().(uint16)) case reflect.Uint32: field[key] = float64(field2.Interface().(uint32)) case reflect.Uint64: field[key] = float64(field2.Interface().(uint64)) case reflect.Float32: field[key] = float64(field2.Interface().(float32)) case reflect.Float64: field[key] = field2.Interface() default: field[key] = field2.Interface() } } _, _ = json.Marshal(p1) // 讀取文件中的數(shù)據(jù),保存為map格式 // 數(shù)據(jù)轉(zhuǎn)化為map時(shí),數(shù)值類型的統(tǒng)一變成float64 data, _ := ioutil.ReadFile('./index.json') fields := make([]map[string]interface{}, 0) err := json.Unmarshal(data, &fields) if err != nil { log.Fatal(err) } // 查詢的條件 columns := []string{'name', 'num'} length := len(columns) for _, item := range fields { for i := 0; i < length; i++ { // 這里的比較需要改進(jìn) if item[columns[i]] != field[columns[i]] {break } if i == length-1 {field = itemgoto OVER } } }OVER: fmt.Println(field) out, _ := json.Marshal(field) _ = json.Unmarshal(out, &product) fmt.Println(product)}
修改操作
修改操作在查詢操作的基礎(chǔ)上實(shí)現(xiàn), 修改操作需要有一個(gè)id值,能確定元素的唯一性.代碼如下:
func Update() { p1 := &Product{ Id: '2bbec87025968879c3c9682abe3bf730', Name: 'John_e', Num: 100, } // 使用反射將struct轉(zhuǎn)化為map tp := reflect.TypeOf(p1).Elem() vp := reflect.ValueOf(p1).Elem() field := make(map[string]interface{}, 0) for i := 0; i < tp.NumField(); i++ { field1 := tp.Field(i) field2 := vp.Field(i) key := field1.Tag.Get('json') switch field2.Kind() { case reflect.Int: field[key] = float64(field2.Interface().(int)) case reflect.Int8: field[key] = float64(field2.Interface().(int8)) case reflect.Int16: field[key] = float64(field2.Interface().(int16)) case reflect.Int32: field[key] = float64(field2.Interface().(int32)) case reflect.Int64: field[key] = float64(field2.Interface().(int64)) case reflect.Uint: field[key] = float64(field2.Interface().(uint)) case reflect.Uint8: field[key] = float64(field2.Interface().(uint8)) case reflect.Uint16: field[key] = float64(field2.Interface().(uint16)) case reflect.Uint32: field[key] = float64(field2.Interface().(uint32)) case reflect.Uint64: field[key] = float64(field2.Interface().(uint64)) case reflect.Float32: field[key] = float64(field2.Interface().(float32)) case reflect.Float64: field[key] = field2.Interface() default: field[key] = field2.Interface() } } _, _ = json.Marshal(p1) // 讀取文件中的數(shù)據(jù),保存為map格式 // 數(shù)據(jù)轉(zhuǎn)化為map時(shí),數(shù)值類型的統(tǒng)一變成float64 data, _ := ioutil.ReadFile('./index.json') fields := make([]map[string]interface{}, 0) err := json.Unmarshal(data, &fields) if err != nil { log.Fatal(err) } // 修改的條件 columns := []string{'name', 'num'} for _, v := range fields { if v['_id'] == field['_id'] { for _, col := range columns {v[col] = field[col] } field = v } } out, _ := json.MarshalIndent(fields, '', ' ') _ = ioutil.WriteFile('./index.json', out, 0755)}
刪除操作
最后就是刪除操作了,這個(gè)比較思路簡(jiǎn)單,輸入唯一的id值,刪除對(duì)應(yīng)的字段,再保存到文件就可以了.代碼如下:
func Delete() { p1 := &Product{ Id: 'db43fa2d4f69cddce7494941cb36032b', Name: 'John_e', Num: 100, } _, _ = json.Marshal(p1) // 讀取文件中的數(shù)據(jù),保存為map格式 // 數(shù)據(jù)轉(zhuǎn)化為map時(shí),數(shù)值類型的統(tǒng)一變成float64 data, _ := ioutil.ReadFile('./index.json') fields := make([]map[string]interface{}, 0) err := json.Unmarshal(data, &fields) if err != nil { log.Fatal(err) } length := len(fields) for index, field := range fields { if field['_id'] == p1.Id { if index == length - 1 {fields = fields[0:index] } else {fields = append(fields[0:index], fields[index+1:]...) } } } out, _ := json.MarshalIndent(fields, '', ' ') _ = ioutil.WriteFile('./index.json', out, 0755)}
完整版
最后在附上完整版代碼:
package storeimport ( 'bytes' 'crypto/md5' 'encoding/json' 'errors' 'fmt' 'io/ioutil' 'os' 'path/filepath' 'reflect' 'strings' 'time')type Store struct { Dir string}func NewStore(dir string) (*Store, error) { // .開頭的為相對(duì)路徑,補(bǔ)全為全路徑 if strings.HasPrefix(dir, '.') { pwd, _ := os.Getwd() dir = filepath.Join(pwd, dir) } store := &Store{Dir: dir} st, err := os.Stat(dir) if err != nil { err = os.Mkdir(dir, 0755) if err != nil { return nil, err } } else if st != nil && !st.IsDir() { return nil, errors.New('file already exists') } return store, nil}// 創(chuàng)建與結(jié)構(gòu)體對(duì)應(yīng)的json文件func (s *Store) Sync(values ...interface{}) error { for _, v := range values { tb := parseTn(v) if tb == '' { return errors.New('does not find store') } _path := filepath.Join(s.Dir, tb) _, err := os.Stat(_path) if err != nil { _ = ioutil.WriteFile(_path, []byte('[]'), 0755) } } return nil}// 刪除所有func (s *Store) Destroy() error { return os.RemoveAll(s.Dir)}func (s *Store) FindAll(v interface{}) error { _path, err := s.before(v) if err != nil { return err } out, err := s.readAll(_path) if err != nil { return err } err = json.Unmarshal(out, &v) return err}func (s *Store) FindOne(v interface{}, columns ...string) (interface{}, error) { _path, err := s.before(v) if err != nil { return nil, err } data, err := s.readAll(_path) if err != nil { return nil, err } fields := make([]map[string]interface{}, 0) err = json.Unmarshal(data, &fields) if err != nil { return nil, err } m := structToMap(v) length := len(columns) for _, item := range fields { for i := 0; i < length; i++ { // TODO 這里的比較需要改進(jìn) if item[columns[i]] != m[columns[i]] {break } if i == length-1 {m = itemgoto OVER } } }OVER: err = mapToStruct(m, &v) if err != nil { return nil, err } return v, nil}func (s *Store) Create(v interface{}) error { _path, err := s.before(v) if err != nil { return err } data, err := s.readAll(_path) if err != nil { return err } fields := make([]map[string]interface{}, 0) err = json.Unmarshal(data, &fields) if err != nil { return err } m := structToMap(v) m['_id'] = randId() fields = append(fields, m) err = s.writeAll(_path, fields) if err != nil { return err } err = mapToStruct(m, v) if err != nil { return err } return nil}func (s *Store) Update(v interface{}, columns ...string) error { _path, err := s.before(v) if err != nil { return err } data, err := s.readAll(_path) if err != nil { return err } fields := make([]map[string]interface{}, 0) err = json.Unmarshal(data, &fields) if err != nil { return err } m := structToMap(v) for _, v := range fields { if v['_id'] == m['_id'] { for _, col := range columns {v[col] = m[col] } m = v } } err = s.writeAll(_path, fields) if err != nil { return err } return nil}func (s *Store) Delete(v interface{}) error { _path, err := s.before(v) if err != nil { return err } data, err := s.readAll(_path) if err != nil { return err } fields := make([]map[string]interface{}, 0) err = json.Unmarshal(data, &fields) if err != nil { return err } m := structToMap(v) length := len(fields) for index, field := range fields { if field['_id'] == m['_id'] { if index == length-1 {fields = fields[0:index] } else {fields = append(fields[0:index], fields[index+1:]...) } } } err = s.writeAll(_path, fields) if err != nil { return err } return nil}func (s *Store) Clean(v interface{}) error { _path, err := s.before(v) if err != nil { return err } return os.Remove(_path)}func (s *Store) readAll(file string) ([]byte, error) { out, err := ioutil.ReadFile(file) if err != nil { return nil, err } return out, nil}func (s *Store) writeAll(file string, v interface{}) error { out, err := json.MarshalIndent(v, '', ' ') if err != nil { return err } err = ioutil.WriteFile(file, out, 0755) if err != nil { return err } return nil}func (s *Store) before(v interface{}) (string, error) { tb := parseTn(v) if tb == '' { return '', errors.New('invalid table name') } _path := filepath.Join(s.Dir, tb) _, err := os.Stat(_path) if err != nil { return '', err } return _path, nil}func structToMap(v interface{}) map[string]interface{} { tp := reflect.TypeOf(v).Elem() vp := reflect.ValueOf(v).Elem() field := make(map[string]interface{}, 0) for i := 0; i < tp.NumField(); i++ { field1 := tp.Field(i) field2 := vp.Field(i) key := field1.Tag.Get('json') field[key] = field2.Interface() switch field2.Kind() { case reflect.Int: field[key] = float64(field2.Interface().(int)) case reflect.Int8: field[key] = float64(field2.Interface().(int8)) case reflect.Int16: field[key] = float64(field2.Interface().(int16)) case reflect.Int32: field[key] = float64(field2.Interface().(int32)) case reflect.Int64: field[key] = float64(field2.Interface().(int64)) case reflect.Uint: field[key] = float64(field2.Interface().(uint)) case reflect.Uint8: field[key] = float64(field2.Interface().(uint8)) case reflect.Uint16: field[key] = float64(field2.Interface().(uint16)) case reflect.Uint32: field[key] = float64(field2.Interface().(uint32)) case reflect.Uint64: field[key] = float64(field2.Interface().(uint64)) case reflect.Float32: field[key] = float64(field2.Interface().(float32)) case reflect.Float64: field[key] = field2.Interface() default: field[key] = field2.Interface() } } return field}func mapToStruct(m map[string]interface{}, v interface{}) error { out, err := json.Marshal(m) if err != nil { return err } return json.Unmarshal(out, &v)}func toSnake(s string) string { out := bytes.Buffer{} bName := []byte(s) point := 0 for index, b := range bName { // 非大寫,不需要轉(zhuǎn)化 if b < 65 || b > 90 || index-point < 2 { out.WriteByte(b) continue } // 首字符大寫,直接轉(zhuǎn)化為小寫 if index == 0 { out.WriteByte(b + 32) point = index } // 連續(xù)三個(gè)大寫,觸發(fā)轉(zhuǎn)化 if index-point >= 2 { out.WriteByte(95) out.WriteByte(b + 32) point = index } } return out.String()}func parseTn(v interface{}) string { var name string tp := reflect.TypeOf(v).Elem() switch tp.Kind() { case reflect.Ptr: sp := strings.Split(tp.String(), '.') name = sp[len(sp)-1] case reflect.Slice: sp := strings.Split(tp.String(), '.') name = sp[len(sp)-1] case reflect.Struct: name = tp.Name() } name = toSnake(name) return name + '.json'}func randId() string { return fmt.Sprintf('%x', md5.Sum([]byte(time.Now().String())))}
到此這篇關(guān)于golang使用json格式實(shí)現(xiàn)增刪查改的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)golang json增刪查改內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. 如何基于Python Matplotlib實(shí)現(xiàn)網(wǎng)格動(dòng)畫2. 利用promise及參數(shù)解構(gòu)封裝ajax請(qǐng)求的方法3. ASP 信息提示函數(shù)并作返回或者轉(zhuǎn)向4. asp(vbs)Rs.Open和Conn.Execute的詳解和區(qū)別及&H0001的說(shuō)明5. ThinkPHP5實(shí)現(xiàn)JWT Token認(rèn)證的過(guò)程(親測(cè)可用)6. Ajax實(shí)現(xiàn)表格中信息不刷新頁(yè)面進(jìn)行更新數(shù)據(jù)7. JSP數(shù)據(jù)交互實(shí)現(xiàn)過(guò)程解析8. windows服務(wù)器使用IIS時(shí)thinkphp搜索中文無(wú)效問(wèn)題9. .NET中l(wèi)ambda表達(dá)式合并問(wèn)題及解決方法10. PHP設(shè)計(jì)模式中工廠模式深入詳解
