歡迎您光臨本站 註冊首頁

golang使用json格式實現增刪查改的實現示例

←手機掃碼閱讀     limiyoyo @ 2020-06-12 , reply:0

需求和思路
 

在一般的小項目或者一個小軟件,例如客戶端之類的小程序中,可能會需要數據的持久化.但是使用一般的數據庫(Mysql)之類的不合適.使用sqlite3這種嵌入式的是個較好的方法,但是Go語言中sqlite3的庫是C語言的,Cgo不支持跨平臺編譯.正是由於這種需求,才想到使用json格式將數據直接保存在文件中.
 具體的思路是怎麼樣呢? 在Go語言中如果要將數據轉化成json格式的話,有兩種格式 struct 和 map. 如果同時需要增刪查改功能的話,將map作為中間格式是比較合適的.接下來我們就來實現它.

查詢操作
 

這種操作的實現比較簡單,直接將文件中的數據讀取出來,使用json庫反序列化就可以了. 代碼如下 :

  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)    }      // 這裡參數要指定為變量的地址    err = json.Unmarshal(data, &ps)    if err != nil {      log.Fatal(err)    }      fmt.Println(ps)  }

 

添加操作
 

添加的實現實在查詢的基礎上的,我們需要先查詢文件中的數據庫,並轉化為map格式,再將struct也轉化為map格式(這裡要使用反射),合併map,json序列化,最後保存在文件中.代碼如下:

  func create() {    fields := make([]map[string]interface{}, 0)        p1 := &Product{      Name: "Blog",      Num: 2,    }        _, _ = json.Marshal(p1)    // 讀取文件中的數據,保存為map格式    data, _ := ioutil.ReadFile("./index.json")    err := json.Unmarshal(data, &fields)    if err != nil {      log.Fatal(err)    }        // 使用反射將struct轉化為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轉化為map,根據輸入的條件查詢.查詢的結果轉化為struct.代碼如下:

  func FindOne() {    product := &Product{}      p1 := &Product{      Name: "John",      Num: 23,    }      // 使用反射將struct轉化為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)    // 讀取文件中的數據,保存為map格式    // 數據轉化為map時,數值類型的統一變成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++ {        // 這裡的比較需要改進        if item[columns[i]] != field[columns[i]] {          break        }        if i == length-1 {          field = item          goto OVER        }      }    }  OVER:    fmt.Println(field)      out, _ := json.Marshal(field)    _ = json.Unmarshal(out, &product)      fmt.Println(product)  }

 

修改操作
 

修改操作在查詢操作的基礎上實現, 修改操作需要有一個id值,能確定元素的唯一性.代碼如下:

  func Update() {    p1 := &Product{      Id:  "2bbec87025968879c3c9682abe3bf730",      Name: "John_e",      Num: 100,    }      // 使用反射將struct轉化為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)    // 讀取文件中的數據,保存為map格式    // 數據轉化為map時,數值類型的統一變成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)  }

 

刪除操作
 

最後就是刪除操作了,這個比較思路簡單,輸入唯一的id值,刪除對應的字段,再保存到文件就可以了.代碼如下:

  func Delete() {    p1 := &Product{      Id:  "db43fa2d4f69cddce7494941cb36032b",      Name: "John_e",      Num: 100,    }      _, _ = json.Marshal(p1)    // 讀取文件中的數據,保存為map格式    // 數據轉化為map時,數值類型的統一變成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 store    import (    "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) {      // .開頭的為相對路徑,補全為全路徑    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  }    // 創建與結構體對應的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 這裡的比較需要改進        if item[columns[i]] != m[columns[i]] {          break        }        if i == length-1 {          m = item          goto 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 {      // 非大寫,不需要轉化      if b < 65 || b > 90 || index-point < 2 {        out.WriteByte(b)        continue      }      // 首字符大寫,直接轉化為小寫      if index == 0 {        out.WriteByte(b + 32)        point = index      }      // 連續三個大寫,觸發轉化      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())))  }

 


[limiyoyo ] golang使用json格式實現增刪查改的實現示例已經有300次圍觀

http://coctec.com/docs/javascript/show-post-238187.html