go基础学习之文件编程总结

Reader对象

创建Reader对象
  1. *NewReader(rd io.Reader) Reader
    • 按照缓冲区默认长度创建Reader对象,Reader对象会从底层io.Reader接口读取尽量多的数据进行缓存。
  2. *NewReaderSize(rd io.Reader, size int) Reader
    • 指定缓冲区长度创建Reader对象
操作Reader对象
  1. (b * Reader) Read(p []byte) (n int, err error)
    • 读取数据存放到字节切片p中,执行结束返回已读取的字节数n和错误err,当字节流结束时,n为0,err为io.EOF
  2. (b * Reader) ReadByte() (c byte, err error)
    • 读取并返回一个字节,如果没有字节可读,则返回错误信息
  3. (b * Reader) ReadBytes(delim byte) (line []byte, err error)
    • 读取数据直到遇到“delim”分隔符,并返回读取的字节序列(包括“delim”),如果分隔符不存在读取所有,返回EOF错误
  4. (b * Reader)ReadLine() (line []byte, isPrefix bool, err error)
    • 读取一行数据,如果一行数据太长,isprefix会被设置为true,返回之前的数据,继续调用返回之后的数据直到遇到换行符
    • 如果是读取一行数据建议使用ReadString('\n')或者ReadBytes('\n')
  5. (b * Reader) ReadRune() (r rune, size int, err error)
    • 读取一个UTF-8编码的字符,并返回字节数
  6. (b * Reader)ReadSlice(delim byte) (line []byte, err error)
    • 读取数据直到遇到分隔符,返回读取的字节切片
  7. (b * Reader) ReadString(delim byte) (line string, err error)
    • 读取数据直到遇到分隔符,返回读取的字符串
  8. (b * Reader)UnreadByte() error
    • 撤销已读最后一个字节,重新放入缓冲区的头部
  9. (b * Reader) UnreadRune() error
    • 撤销已读最后一个字符,重新放入缓冲区的头部
  10. (b * Reader) Buffered() (n int, err error)
    • 返回可从缓冲区读出数据的字节数
  11. (b * Reader) Peek(n int) ([]byte], err error)
    • 读取指定字节的数据,读取的数据不会从缓冲区清除

Writer对象

创建Writer对象
  1. NewWriter(wr io.Writer) * Writer
    • 按照默认缓冲区长度创建
  2. NewWriterSize(wr io.Writer, size int) * Writer
    • 指定缓冲区长度
操作Writer 对象
  1. (b * Writer) Available() int
    • 返回缓冲区中未使用的字节数
  2. (b * Writer) Buffered() int
    • 返回已写入当前缓冲区中的字节数
  3. (b * Writer) Flush() error
    • 将缓冲区的数据写入底层io.Writer
  4. (b * Writer) Write(p []byte) (nn int, err error)
    • 将字节切片写入缓冲区,返回已经写入的字节数
  5. (b * Writer) WriteByte(c byte) error
    • 写入一个字节
  6. (b * Writer) WriteRune(r rune) (size int, err error)
    • 写入一个Unicode字符,返回写入的字节数
  7. (b * Writer) WriteString(s string) (int, error)
    • 写入一个字符串,返回写入的字节数

读写文件操作案例

打开文件和关闭文件

  • func Open(name string) (file * File, err error)

    以O_RDONLY只读模式打开文件

  • func ( * File)Close() error

    关闭文件

读文件

  1. 读取文件内容并显示在终端(带缓冲区的方式)

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    func main() {
    	file, err := os.Open("C:\\Users\\zhouzy1\\Desktop\\my_study_notes\\go学习\\代码\\study_go\\day1\\abc.txt")
    	if err != nil {
    		fmt.Println("打开文件错误:",err)
    	}
    	// 打开文件一定记得最后关闭
    	defer file.Close()
    
    	// 默认缓冲区大小为4096
    	reader := bufio.NewReader(file)
    	for {
    		str, err := reader.ReadString('\n')
    		fmt.Print(str)
    		if err == io.EOF { // 文件结束符为EOF
    			break
    		}
    	}
    }
    
  2. 一次性读取文件所有内容至缓冲区中,适用于文件不大的情况:

    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    )
    
    func main() {
    	file := "C:\\Users\\zhouzy1\\Desktop\\my_study_notes\\go学习\\代码\\study_go\\day1\\abc.txt"
    	content, err := ioutil.ReadFile(file)
    	if err != nil {
    		fmt.Printf("read file err=%v", err)
    	}
    	fmt.Printf("%v", string(content))
    }
    
  3. 按行读取文件

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    func main() {
    	path := "C:\\Users\\zhouzy1\\Desktop\\my_study_notes\\go学习\\代码\\study_go\\day1\\abc.txt"
    	f, err := os.Open(path)
    	if err != nil {
    		fmt.Println("err = ", err)
    		return
    	}
    	defer f.Close()
    
    	r := bufio.NewReader(f)
    	for {
    		buf, err := r.ReadBytes('\n')
    		if err != nil {
    			if err == io.EOF {
    				break
    			}
    			fmt.Println("err = ", err)
    		}
    		fmt.Printf("buf = #%s#\n", string(buf))
    	}
    }
    

写文件

  • os.OpenFile(name string, flag int, perm FileMode) (file * File, err error)

    指定模式指定权限打开文件

  1. 打开或者创建文件并写入内容

    package main
    
    import (
       "bufio"
       "fmt"
       "os"
    )
    
    func main() {
       filePath := "a.txt"
       file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_CREATE, 0666)
       if err != nil {
          fmt.Printf("open file err=%v\n", err)
          return
       }
       defer file.Close()
    
       str := "hello go!"
       writer := bufio.NewWriter(file)
       for i := 0; i < 5; i++ {
          writer.WriteString(str)
       }
       // 使用的缓冲区写入,flush后才会将缓冲区的内容写入文件
       writer.Flush()
    }
    
  2. 打开文件,写入并覆盖原有内容

    package main
    
    import (
       "bufio"
       "fmt"
       "os"
    )
    
    func main() {
       filePath := "a.txt"
       file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_TRUNC, 0666)
       if err != nil {
          fmt.Printf("open file err=%v\n", err)
          return
       }
       defer file.Close()
    
       str := "覆盖原有内容!"
       writer := bufio.NewWriter(file)
       for i := 0; i < 5; i++ {
          writer.WriteString(str)
       }
       // 使用的缓冲区写入,flush后才会将缓冲区的内容写入文件
       writer.Flush()
    }
    
  3. 打开文件,追加内容

    package main
    
    import (
       "bufio"
       "fmt"
       "os"
    )
    
    func main() {
       filePath := "a.txt"
       file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_APPEND, 0666)
       if err != nil {
          fmt.Printf("open file err=%v\n", err)
          return
       }
       defer file.Close()
    
       str := "追加内容!\r\n"
       writer := bufio.NewWriter(file)
       for i := 0; i < 5; i++ {
          writer.WriteString(str)
       }
       // 使用的缓冲区写入,flush后才会将缓冲区的内容写入文件
       writer.Flush()
    }
    
  4. 打开文件,读取文件内容,并追加内容

    package main
    
    import (
       "bufio"
       "fmt"
       "io"
       "os"
    )
    
    func main() {
       filePath := "a.txt"
       file, err := os.OpenFile(filePath, os.O_RDWR | os.O_APPEND, 0666)
       if err != nil {
          fmt.Printf("open file err=%v\n", err)
          return
       }
       defer file.Close()
    
       reader := bufio.NewReader(file)
       for {
          str, err := reader.ReadString('\n')
          if err == io.EOF {
             break
          }
          fmt.Print(str)
       }
    
       str := "追加内容!\r\n"
       writer := bufio.NewWriter(file)
       for i := 0; i < 5; i++ {
          writer.WriteString(str)
       }
       // 使用的缓冲区写入,flush后才会将缓冲区的内容写入文件
       writer.Flush()
    }
    
  5. 读取一个文件的内容写入另一个文件

    package main
    
    import (
       "fmt"
       "io/ioutil"
    )
    
    func main() {
       file1Path := "a.txt"
       file2Path := "b.txt"
       data, err := ioutil.ReadFile(file1Path)
       if err != nil {
          fmt.Printf("read file err = %v\n", err)
          return
       }
       err = ioutil.WriteFile(file2Path, data, 0666)
       if err != nil {
          fmt.Printf("write file error = %v\n", err)
       }
    }
    

判断文件是否存在

  • 判断文件或者文件夹是否存在
package main

import (
	"fmt"
	"os"
)

func main() {
	file1Path := "a.txt"
	file2Path := "not_exit_file.txt"
	fileInfo, err := os.Stat(file1Path)
	_, err2 := os.Stat(file2Path)
	// 如果err 为nil 说明文件一定存在
	if err == nil {
		fmt.Println("文件存在")
	}

	fmt.Printf("%T\n", fileInfo)
	// 文件名
	fmt.Println(fileInfo.Name())
	// 文件大小
	fmt.Println(fileInfo.Size())
	// 是否是目录
	fmt.Println(fileInfo.IsDir())
	// 修改时间
	fmt.Println(fileInfo.ModTime())

	// 如果err 不为nil 需要通过os.IsNotExist判断错误类型为不存在
	// 否则可能为别的错误类型
	if os.IsNotExist(err2) {
		fmt.Println("文件不存在2")
	}
}

命令行参数

  • 使用os.Args 存储所有的命令行参数
  • flag 包解析命令行参数
package main

import (
   "flag"
   "fmt"
)

func main() {
   var user string
   var pwd string
   var host string
   var port int
   flag.StringVar(&user, "u", "", "用户名默认为空")
   flag.StringVar(&pwd, "p", "", "密码默认为空")
   flag.StringVar(&host, "h", "localhost", "主机名默认为localhost")
   flag.IntVar(&port, "port", 3306, "端口默认为3306")
   flag.Parse()
   fmt.Printf("user=%v pwd=%v host=%v port=%v",
      user, pwd, host, port)
}

断点续传

Seeker接口
  • Seeker是包装基本Seek方法的接口
package main

import (
   "fmt"
   "io"
   "os"
)

func main() {
   /**
   seek(offset, whence), 设置指针光标的位置
   第一个参数:偏移量
   第二个参数:如何设置
      0: seekStart 表示相对于文件开始
      1: seekCurrent 表示相对于当前偏移量
      2: seek end 表示相对于结束
   const (
      SeekStart = 0
      SeekCurrent = 1
      SeekEnd    = 2
   )
   随机读取文件:
      可以设置指针光标的位置
    */
   file, _ := os.OpenFile("a.txt", os.O_RDWR, 0)
   defer file.Close()
   bs := []byte{0, 1}
   file.Read(bs)
   fmt.Println(string(bs))
   file.Seek(4, io.SeekStart)
   file.Read(bs)
   fmt.Println(string(bs))
   file.Seek(2, 0)
   file.Read(bs)
   fmt.Println(string(bs))
   file.Seek(3, io.SeekCurrent)
   file.Read(bs)
   fmt.Println(string(bs))
   file.Seek(0, io.SeekEnd)
   file.WriteString("ABC")
}
实现案例
  • 实现断点续传,主要要记录读写文件位置,实现思路:在读写文件的同时,建立一个临时文件用于同步读写数据的位置,当需要断点续传的时候,从临时文件中获取指定位置,然后通过Seek()方法定位读写位置,继续读写。

    package main
    
    import (
       "fmt"
       "io"
       "os"
       "strconv"
    )
    
    func main() {
       /*
       断点续传:
       复制文件a.png 复制到b.png
        */
    
       srcFile := "a.png"
       destFile := "b.png"
       tmpFIle := destFile + "tmp.txt"
    
       file1, _ := os.Open(srcFile)
       file2, _ := os.OpenFile(destFile, os.O_CREATE | os.O_WRONLY, os.ModePerm)
       file3, _ := os.OpenFile(tmpFIle, os.O_CREATE | os.O_RDWR, os.ModePerm)
       defer file1.Close()
       defer file2.Close()
    
       // 1. 读取临时文件中的数据,根据seek
       file3.Seek(0, io.SeekStart)
       bs := make([]byte, 100, 100)
       n1, err := file3.Read(bs)
       fmt.Println(n1)
       countStr := string(bs[:n1])
       fmt.Println(countStr)
       count, _ := strconv.ParseInt(countStr, 10, 64)
       fmt.Println(count)
    
       // 2. 设置读,写的偏移量
       file1.Seek(count, 0)
       file2.Seek(count, 0)
       data := make([]byte, 1024, 1024)
       n2 := -1
       n3 := -1
       total := int(count)
    
       for {
          // 3.读取数据
          n2, err = file1.Read(data)
          if err == io.EOF {
             fmt.Println("文件复制完毕")
             file3.Close()
             os.Remove(tmpFIle)
             break
          }
          // 将数据写入目标文件
          n3, _ = file2.Write(data[:n2])
          total += n3
          // 将复制总量,存储到临时文件中
          file3.Seek(0, io.SeekStart)
          file3.WriteString(strconv.Itoa(total))
          if total > 1024{
             panic("异常断开")
          }
       }
    }
    

读写JSON文件

写入JSON文件

package main

import (
   "encoding/json"
   "fmt"
   "os"
)

type Website struct {
   Name string `xml:"name, attr"`
   Url string
   Course []string
}

func main() {
   info := []Website{
      {"Golang", "http://清华尹成大神/golang/",
      []string{"http://清华尹成大神/cplus/", "http://清华尹成大神/linux_tutorial/"}},
      {"Java", "http://清华尹成大神/java/",
         []string{"http://清华尹成大神/socket/", "http://清华尹成大神/python/"}},
   }
   filePtr, err := os.Create("info.json")
   if err != nil {
      fmt.Println("err:", err.Error())
      return
   }
   defer filePtr.Close()
   encoder := json.NewEncoder(filePtr)
   err = encoder.Encode(info)
   if err != nil {
      fmt.Println("编码错误", err.Error())
   }else {
      fmt.Println("success")
   }
}

读取JSON文件

package main

import (
   "encoding/json"
   "fmt"
   "os"
)

type Website struct {
   Name string `xml:"name, attr"`
   Url string
   Course []string
}

func main() {
   filePtr, err := os.Open("info.json")
   if err != nil {
      fmt.Println("文件打开失败【err:%s】", err.Error())
      return
   }
   defer filePtr.Close()
   var info []Website
   // 创建json解码器
   decoder := json.NewDecoder(filePtr)
   err = decoder.Decode(&info)
   if err != nil {
      fmt.Println("解码失败", err.Error())
   } else {
      fmt.Println("解码成功")
      fmt.Println(info)
   }
}

读写XML文件

写入xml文件

package main

import (
   "encoding/xml"
   "fmt"
   "os"
)

type Website struct {
   Name string `xml:"name, attr"`
   Url string
   Course []string
}

func main() {
   info := Website{"清华尹成大神网", "http://清华尹成大神/golang/",
      []string{"Go语言入门教程", "Golang入门教程"}}
   f, err := os.Create("info.xml")
   if err != nil {
      fmt.Println("文件创建失败", err.Error())
      return
   }
   defer f.Close()
   // 序列化到文件中
   encoder := xml.NewEncoder(f)
   err = encoder.Encode(info)
   if err != nil {
      fmt.Println("编码错误:", err.Error())
      return
   } else {
      fmt.Println("编码成功")
   }
}

读XML文件

package main

import (
   "encoding/xml"
   "fmt"
   "os"
)

type Website struct {
   Name string `xml:"name, attr"`
   Url string
   Course []string
}

func main() {
   f, err := os.Open("info.xml")
   if err != nil {
      fmt.Println("文件打开失败", err.Error())
      return
   }
   defer f.Close()
   info := Website{}

   // 创建xml解码器
   decoder := xml.NewDecoder(f)
   err = decoder.Decode(&info)
   if err != nil {
      fmt.Println("解码错误:", err.Error())
      return
   } else {
      fmt.Println("解码成功")
      fmt.Println(info)
   }
}

读写gob文件

  • gob go语言自己以二进制形式序列化和反序列化程序数据的格式
  • 编码和解码过程中用到了Go的反射,通常用于远程方法调用参数和结果的传输,以及机器和程序之间的数据传输
  • 零值会被忽略

创建gob文件

package main

import (
   "encoding/gob"
   "fmt"
   "os"
)

func main() {
   info := map[string]string{
      "name": "清华大声",
      "website": "badidu.com",
   }
   name := "demo.gob"
   File, _ := os.OpenFile(name, os.O_RDWR|os.O_CREATE,0777)
   defer File.Close()
   enc := gob.NewEncoder(File)
   if err := enc.Encode(info); err != nil {
      fmt.Println(err)
   }
}

读取gob文件

package main

import (
   "encoding/gob"
   "fmt"
   "os"
)

func main() {
   var M map[string]string
   File, _ := os.Open("demo.gob")
   D := gob.NewDecoder(File)
   D.Decode(&M)
   fmt.Println(M)
}

自定义二进制文件读写

写自定义二进制文件

package main

import (
   "bytes"
   "encoding/binary"
   "fmt"
   "os"
)


type Website struct {
   Url int32
}

func main() {
   file, err := os.Create("output.bin")
   for i := 1; i <= 10; i++ {
      info := Website{Url: int32(i)}

      if err != nil {
         fmt.Println("文件创建失败")
         return
      }
      defer file.Close()
      var bin_buf bytes.Buffer
      binary.Write(&bin_buf, binary.LittleEndian, info)
      b := bin_buf.Bytes()
      _, err = file.Write(b)
      if err != nil {
         fmt.Println("编码失败", err.Error())
         return
      }
   }
   fmt.Println("编码成功")
}

读二进制文件

package main

import (
   "bytes"
   "encoding/binary"
   "fmt"
   "os"
)

type Website struct {
   Url int32
}

func main() {
   file, err := os.Open("output.bin")
   defer file.Close()
   if err != nil {
      fmt.Println("文件打开失败", err.Error())
      return
   }
   m := Website{}
   for i := 1; i <= 10; i++ {
      data := readNextBytes(file, 4)
      buffer := bytes.NewBuffer(data)
      err = binary.Read(buffer, binary.LittleEndian, &m)
      if err != nil {
         fmt.Println("二进制文件读取失败", err)
         return
      }
      fmt.Println(i)
   }
}

func readNextBytes(file *os.File, number int) []byte {
   bytes := make([]byte, number)
   _, err := file.Read(bytes)
   if err != nil {
      fmt.Println("解码失败",err)
   }
   return bytes
}

zip归档文件的读写操作

创建zip归档文件

package main

import (
   "archive/zip"
   "bytes"
   "fmt"
   "os"
)

func main() {
   // 使用buffer创建压缩文档
   buf := new(bytes.Buffer)
   w := zip.NewWriter(buf)
   // 将文件加入压缩文档
   var files = []struct{
      Name, Body string
   }{
      {"Golang.txt", "清华大神"},
   }
   for _, file := range files {
      f, err := w.Create(file.Name)
      if err != nil {
         fmt.Println(err)
      }
      _, err = f.Write([]byte(file.Body))
      if err != nil {
         fmt.Println(err)
      }
   }
   // 关闭压缩文档
   err := w.Close()
   if err != nil {
      fmt.Println(err)
   }
   // 将压缩文档内容写入文件
   f, err := os.OpenFile("file.zip", os.O_CREATE|os.O_WRONLY, 0666)
   if err != nil {
      fmt.Println(err)
   }
   buf.WriteTo(f)
}

读取zip归档文件

package main

import (
   "archive/zip"
   "fmt"
   "io"
   "os"
)

func main() {
   // 打开一个zip格式文件
   r, err := zip.OpenReader("file.zip")
   if err != nil {
      fmt.Printf(err.Error())
   }
   defer r.Close()
   // 迭代压缩文件中的文件,打印文件中的内容
   for _,f := range r.File {
      fmt.Printf("文件名:%s\n", f.Name)
      rc, err := f.Open()
      if err != nil {
         fmt.Printf(err.Error())
      }
      _, err = io.CopyN(os.Stdout, rc, int64(f.UncompressedSize64))
      if err != nil {
         fmt.Printf(err.Error())
      }
      rc.Close()
   }
}

tar归档文件的读写操作

打包tar文件

package main

import (
   "archive/tar"
   "fmt"
   "io"
   "os"
)

func main() {
   // 创建tar文件
   f, err := os.Create("./output.tar")
   if err != nil {
      fmt.Println(err)
      return
   }
   defer f.Close()
   tw := tar.NewWriter(f)
   defer tw.Close()
   // 获取文件相关信息
   fileInfo, err := os.Stat("./main.go")
   if err != nil {
      fmt.Println(err)
   }
   hdr, err := tar.FileInfoHeader(fileInfo, "")
   if err != nil {
      fmt.Println(err)
   }
   err = tw.WriteHeader(hdr)
   if err != nil {
      fmt.Println(err)
   }
   f1, err := os.Open("./main.go")
   if err != nil {
      fmt.Println(err)
      return
   }
   m, err := io.Copy(tw, f1)
   if err != nil {
      fmt.Println(err)
   }
   fmt.Println(m)
}

解压tar归档文件

package main

import (
   "archive/tar"
   "fmt"
   "io"
   "os"
)

func main() {
   // 创建tar文件
   f, err := os.Create("./output.tar")
   if err != nil {
      fmt.Println(err)
      return
   }
   defer f.Close()
   tw := tar.NewWriter(f)
   defer tw.Close()
   // 获取文件相关信息
   fileInfo, err := os.Stat("./main.go")
   if err != nil {
      fmt.Println(err)
   }
   hdr, err := tar.FileInfoHeader(fileInfo, "")
   if err != nil {
      fmt.Println(err)
   }
   err = tw.WriteHeader(hdr)
   if err != nil {
      fmt.Println(err)
   }
   f1, err := os.Open("./main.go")
   if err != nil {
      fmt.Println(err)
      return
   }
   m, err := io.Copy(tw, f1)
   if err != nil {
      fmt.Println(err)
   }
   fmt.Println(m)
}

文件锁操作

  • flock是对于整个文件的建议性锁。也就是说,如果一个进程在一个文件上放了锁,其他进程是可以知道的。
  • 它的第一个参数是文件描述符,在文件描述符关闭时,锁会自动释放。而当进程终止时,所有的文件描述符均会被关闭
  • flock主要三种操作类型:
    • LOCK_SH: 共享锁,多个进程可以使用同一把锁,常被用作读共享锁
    • LOCK_EX: 排它锁,同时只允许一个进程使用,常备用所写锁
    • LOCK_UN: 释放锁

json(反)序列化技巧

使用json tag 指定字段名

type Person struct {
   Name string `json:"name"`
   Age int64
   Weight float64
}

忽略某个字段

type Person struct {
   Name string `json:"name"`
   Age int64
   Weight float64 `json:"-"`
}

忽略空值字段

type Person struct {
   Name string `json:"name"`
   Age int64  `json:"age,omitempty"`
   Weight float64 `json:"-"`
}

忽略嵌套结构体空值字段

  • 嵌套结构体嵌套序列化显示需要使用指针
type Profile struct {
   Website string `json:"website"`
   Slogan string `json:"slogan"`
}
type User struct {
   Name string `json:"name"`
   Email string `json:"email,omitempty"`
   *Profile `json:"profile,omitempty"`    
}

不修改原结构体忽略空值字段

  • 创建另外的结构体匿名嵌套原结构体,并制定字段为匿名结构体指针类型
type User struct {
   Name string `json:"name"`
   Password string `json:"password"`
}

type PublicUser struct {
   *User
   Password *struct{} `json:"password,omitempty"`
}

优雅处理字符串格式的数字

package main

import (
   "encoding/json"
   "fmt"
)

func main() {

   type Card struct {
      ID int64 `json:"id,string"`
      Score float64 `json:"score,string"`
   }

   jsonStr := `{"id": "12345", "score": "88.5"}`
   var c Card
   if err := json.Unmarshal([]byte(jsonStr), &c); err != nil {
      fmt.Printf("json.Unmarsha jsonStr failed, err:%v\n", err)
      return
   }
   fmt.Printf("c:%#v\n", c)
}

整数变浮点数

  • JSON协议没有整型和浮点型之分,统称为number。JSON反序列化后都会转为float64:

    package main
    
    import (
       "encoding/json"
       "fmt"
    )
    
    func main() {
       var m = make(map[string]interface{}, 1)
       m["count"] = 1
       b, err := json.Marshal(m)
       if err != nil {
          fmt.Printf("marshal failed, err:%v\n", err)
       }
       fmt.Printf("str:%#v\n", string(b))
    
       var m2 map[string]interface{}
       err = json.Unmarshal(b, &m2)
       if err != nil{
          fmt.Printf("unmarshal failed, err:%v\n", err)
          return
       }
       fmt.Printf("value:%v\n", m2["count"])  //1
       fmt.Printf("type::%T\n", m2["count"])  // float64
    }
    

想要更合理的处理数字需要使用decoder:

package main

import (
   "bytes"
   "encoding/json"
   "fmt"
)

func main() {
   var m = make(map[string]interface{}, 1)
   m["count"] = 1
   b, err := json.Marshal(m)
   if err != nil {
      fmt.Printf("marshal failed, err:%v\n", err)
   }
   fmt.Printf("str:%#v\n", string(b))

   var m2 map[string]interface{}
   // 使用decoder方式反序列化,指定使用number类型
   decoder := json.NewDecoder(bytes.NewReader(b))
   decoder.UseNumber()
   err = decoder.Decode(&m2)
   if err != nil{
      fmt.Printf("unmarshal failed, err:%v\n", err)
      return
   }
   fmt.Printf("value:%v\n", m2["count"])
   fmt.Printf("type::%T\n", m2["count"])
   // 将m2["count"]转为json.Number之后调用Int64()方法获得int64类型的值
   count, err := m2["count"].(json.Number).Int64()
   if err != nil {
      fmt.Printf("parse to int64 failed, err:%v\n", err)
      return
   }
   fmt.Printf("type:%T\n", int(count)) //int  
}

使用匿名结构体添加字段

package main

import (
   "encoding/json"
   "fmt"
)

func main() {
   type UserInfo struct {
      ID int `json:"id"`
      Name string `json:"name"`
   }

   u1 := UserInfo{
      ID:   12345,
      Name: "zzy",
   }
   // 使用匿名结构体内嵌User并添加额外字段Token
   b, err := json.Marshal(struct {
      *UserInfo
      Token string `json:"token"`
   }{
      &u1,
      "9asd2d35asd",
   })
   if err != nil {
      fmt.Printf("json.Marsha failed, err:%v\n", err)
      return
   }
   fmt.Printf("str:%s\n", b) 
   // str:{"id":12345,"name":"zzy","token":"9asd2d35asd"}
}

使用匿名结构体组合多个结构体

package main

import (
   "encoding/json"
   "fmt"
)

func main() {
   type Comment struct {
      Content string
   }
   type Image struct {
      Title string `json:"title"`
      URL string `json:"url"`
   }

   c1 := Comment {
      Content: "永远不要高估自己",
   }
   i1 := Image{
      Title: "赞赏码",
      URL: "demo.com",
   }
   b, err := json.Marshal(struct {
      *Comment
      *Image
   }{&c1, &i1})
   if err != nil {
      fmt.Printf("json.Marshal failed, err:%v\n", err)
      return
   }
   fmt.Printf("str:%s\n", b)

   // 反序列化
   jsonStr := `{"Content":"永远不要高估自己","title":"赞赏码","url":"https://www.liwenzhou.com/images/zanshang_qr.jpg"}`
   var (
      c2 Comment
      i2 Image
   )
   if err := json.Unmarshal([]byte(jsonStr), &struct {
      *Comment
      *Image
   }{&c2, &i2});err != nil {
      fmt.Printf("json.Unmarshal failed, err:%v\n", err)
      return
   }
   fmt.Printf("c2:%#v i2%$v\n", c2, i2)
}

处理不确定层级的json

package main

import (
   "encoding/json"
   "fmt"
)

func main() {
   type sendMsg struct {
      User string `json:"user"`
      Msg string `json:"msg"`
   }

   jsonStr := `{"sendMsg":{"user":"q1mi","msg":"永远不要高估自己"},"say":"Hello"}`
   // 定义一个map, value 类型为json.RawMessage, 方便后续更灵活的处理
   var data map[string]json.RawMessage
   if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
      fmt.Printf("1json.Unmarshal jsonStr failed, err: %v\n",err)
      return
   }

   var msg sendMsg
   if err := json.Unmarshal(data["sendMsg"], &msg); err != nil {
      fmt.Printf("json.Unmarshal failed, err:%v\n", err)
      return
   }
   fmt.Printf("msg:%#v\n", msg)
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一切如来心秘密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值