go 语言之文件操作***

基本介绍

文件并不陌生,文件是数据源(保存数据的地方)的一种,例如经常使用的word文档,txt文件,Excel文件都是文件,文件最重要的作用就是保存数据,它既可以保存一张图片,也可以保存视频声音

文件在程序中是以流的形式来操作的

image

 流:数据在数据源(文件)和程序(内存)之间经历的路径

输入流: 数据从数据源(文件)到程序(内存)的路径

输出流:数据从程序(内存)到数据源(文件)的路径

操作

os.File 封装了所有文件相关的操作

image

 File代表一个打开的文件对象

image

文件基本操作

打开文件

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

Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。

关闭文件

func (f *File) Close() error
File.Close()

  示例

package main
import(
	"os"
	"fmt"
)
func main(){
	//大开文件
	//file 对象
	//
	file,err := os.Open("D:/课程资料/crict.yaml")
	if err !=nil{
		fmt.Println("open file err =",err)
	}else{
		fmt.Printf("文件内容=%v",file)
	}
	err = file.Close()
	if err != nil {
		fmt.Println("close file err=",err)
	}
}
// 执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\deom01\main.go
// 文件内容=&{0xc000070a08}
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\deom01\main.go
// 文件内容=&{0xc000070a08}
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\deom01\main.go
// open file err = open D:/课程资料/crictl0.yaml: The system cannot find the file specified.
// close file err= invalid argument

  文件读取操作

1)读取文件的内容并显示在终端(带缓冲区的方式),使用os.Open,file.Close,bufio.NewReader(),reader.ReadString函数和方法

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)
func main(){
	//file,err:=os.Open("")
	
	file,err := os.Open("D:/BaiduNetdiskDownload/第5章-基于云原生分布式存储Ceph实现K8S数据持久化/做实验需要的资料/cephfs-pod-1.yaml")
	if err !=nil{
		fmt.Println("open file err =",err)
	}
	defer file.Close()//及时关闭文件
	//创建一个*Reade,默认4096字节
	/*const (
	defaultBufSize = 4096
	)*/
	reade := bufio.NewReader(file)
	for {
		str,err:=reade.ReadString('\n') //读到换行符结束一行
		if err == io.EOF{ //io.EOF,表示文件结尾
			break
		}
		fmt.Print(str) 
	}

}
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\deom02\mian.go
// apiVersion: v1
// kind: Pod
// metadata:
//   name: cephfs-pod-1
// spec:
//   containers:
//     - image: nginx
//       name: nginx
//       imagePullPolicy: IfNotPresent
//       volumeMounts:
//       - name: test-v1
//         mountPath: /mnt
//   volumes:
//   - name: test-v1
//     persistentVolumeClaim:
//       claimName: cephfs-pvc

  2)读取文件的内容并显示在终端(使用os.ReadFile一次性将整个文件读取到内存中),这种方式不适用于文件不大的情况,相关方法和函数os.ReadFile(ioutil.ReadFile 从 Go 1.16 开始,ioutil.ReadFile 已经不推荐使用了 )  

package main

import (
	"fmt"
	"os"
	//"strings"
)
func main(){
	//file,err:=os.Open("")
	
	file :="D:/BaiduNetdiskDownload/第5章-基于云原生分布式存储Ceph实现K8S数据持久化/做实验需要的资料/cephfs-pvc.yaml"
	t,err :=os.ReadFile(file)
	if err!=nil{
		return
	}
	fmt.Printf("%v",string(t))//t 默认是byte 切片所有这里需要使用强转转为string类型
}
// 执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\deom03\mian.go
// kind: PersistentVolumeClaim
// apiVersion: v1
// metadata:
//   name: cephfs-pvc
// spec:
//   accessModes:
//     - ReadWriteMany
//   volumeName: cephfs-pv
//   resources:
//     requests:
//       storage: 1Gi

  bufio.Scanner  每行不能超过64kb,否则报错

package main

import (
	"bufio"
	"fmt"
	"os"
	//"strings"
)
func main(){
	//file,err:=os.Open("")
	
	// file :="D:/BaiduNetdiskDownload/第5章-基于云原生分布式存储Ceph实现K8S数据持久化/做实验需要的资料/cephfs-pvc.yaml"//只适合小文件
	// t,err :=os.ReadFile(file)
	// if err!=nil{
	// 	return
	// }
	// fmt.Printf("%v",string(t))//t 默认是byte 切片所有这里需要使用强转转为string类型
	s,err:= os.Open("D:/BaiduNetdiskDownload/第5章-基于云原生分布式存储Ceph实现K8S数据持久化/做实验需要的资料/cephfs-pvc.yaml")
	if err !=nil{
		return
	}
	defer s.Close()
	t :=bufio.NewScanner(s)
	for t.Scan() { //此方法返回布尔值
		line := t.Text() // 当前行
		fmt.Println(line)
	}
	if err := t.Err(); err != nil {
		fmt.Println("读取错误:", err)
	} 
}
// 执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\deom03\mian.go
// kind: PersistentVolumeClaim
// apiVersion: v1
// metadata:
//   name: cephfs-pvc
// spec:
//   accessModes:
//     - ReadWriteMany
//   volumeName: cephfs-pv
//   resources:
//     requests:
//       storage: 1Gi

  写文件操作

func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
OpenFile是一个更一般性的文件打开函数,大多数调用者都应用Open或Create代替本函数。它会使用指定的选项(如O_RDONLY等)、指定的模式(如0666等)打开指定名称的文件。如果操作成功,返回的文件对象可用于I/O。如果出错,错误底层类型是*PathError。

 第二个参数:文件打开模式(可以组合)

const (
    O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
    O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
    O_RDWR   int = syscall.O_RDWR   // 读写模式打开文件
    O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
    O_CREATE int = syscall.O_CREAT  // 如果不存在将创建一个新文件
    O_EXCL   int = syscall.O_EXCL   // 和O_CREATE配合使用,文件必须不存在
    O_SYNC   int = syscall.O_SYNC   // 打开文件用于同步I/O
    O_TRUNC  int = syscall.O_TRUNC  // 如果可能,打开时清空文件
)

  第三个参数:权限控制  

r ->4
w->2
x ->1


const (
    // 单字符是被String方法用于格式化的属性缩写。
    ModeDir        FileMode = 1 << (32 - 1 - iota) // d: 目录
    ModeAppend                                     // a: 只能写入,且只能写入到末尾
    ModeExclusive                                  // l: 用于执行
    ModeTemporary                                  // T: 临时文件(非备份文件)
    ModeSymlink                                    // L: 符号链接(不是快捷方式文件)
    ModeDevice                                     // D: 设备
    ModeNamedPipe                                  // p: 命名管道(FIFO)
    ModeSocket                                     // S: Unix域socket
    ModeSetuid                                     // u: 表示文件具有其创建者用户id权限
    ModeSetgid                                     // g: 表示文件具有其创建者组id的权限
    ModeCharDevice                                 // c: 字符设备,需已设置ModeDevice
    ModeSticky                                     // t: 只有root/创建者能删除/移动文件
    // 覆盖所有类型位(用于通过&获取类型位),对普通文件,所有这些位都不应被设置
    ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
    ModePerm FileMode = 0777 // 覆盖所有Unix权限位(用于通过&获取类型位)
)

  示例1创建新文件写入

package main

import (
	"bufio"
	"fmt"
	"os"
	//"strings"
)
func main(){
	//1.打开文件
	file,err:= os.OpenFile("d:/abc.txt",os.O_WRONLY | os.O_CREATE,0666)
	if err!=nil{
		fmt.Printf("open file %v\n",err)
		return
	}
	defer file.Close()
	//准备写入内容
	str := "hello,Gardon\n"
	//写入时使用带缓存的*Writer
	Writer:=bufio.NewWriter(file)
	for i:=0;i<5;i++{
		Writer.WriteString(str)
	}
	//因此writer 带缓存到内存的,因此要同步磁盘
	Writer.Flush()//同步到磁盘
	//
}

  示例2 修改源文件内容;os.O_TRUNC

package main

import (
	"bufio"
	"fmt"
	"os"
	//"strings"
)
func main(){
	//1.打开文件
	file,err:= os.OpenFile("d:/abc.txt", os.O_WRONLY|os.O_TRUNC,0666)
	if err!=nil{
		fmt.Printf("open file %v\n",err)
		return
	}
	defer file.Close()
	//准备写入内容
	str := "你好晨曦\r\n"
	//写入时使用带缓存的*Writer
	Writer:=bufio.NewWriter(file)
	for i:=0;i<10;i++{
		Writer.WriteString(str)
	}
	//因此writer 带缓存到内存的,因此要同步磁盘
	Writer.Flush()//同步到磁盘
	//
}

  打开已存在的文件在原来文件追加 'ABC!ENGLISH!'

package main

import (
	"bufio"
	"fmt"
	"os"
	//"strings"
)
func main(){
	//1.打开文件
	file,err:= os.OpenFile("d:/abc.txt", os.O_WRONLY|os.O_APPEND,0666)
	if err!=nil{
		fmt.Printf("open file %v\n",err)
		return
	}
	defer file.Close()
	//准备写入内容
	str := "'ABC!ENGLISH!\r\n'"
	//写入时使用带缓存的*Writer
	Writer:=bufio.NewWriter(file)
	for i:=0;i<10;i++{
		Writer.WriteString(str)
	}
	//因此writer 带缓存到内存的,因此要同步磁盘
	Writer.Flush()//同步到磁盘
	//
}

  打开已存在的文件,将原来内容显示,并在后面追加5“hello,北京”

方式1

package main

import (
	"bufio"
	"fmt"
	"os"
	//"strings"
)
func main(){
	file2,err2 := os.Open("D:/abc.txt")
	if err2 !=nil{
		fmt.Println("open file err =",err2)
	}
	defer file2.Close()
	t := bufio.NewScanner(file2)
	for t.Scan(){
		line := t.Text() // 当前行
		fmt.Println(line)
	}
	//1.打开文件
	file,err:= os.OpenFile("d:/abc.txt", os.O_WRONLY|os.O_APPEND,0666)
	if err!=nil{
		fmt.Printf("open file %v\n",err)
		return
	}
	defer file.Close()
	//准备写入内容
	str := "'hello,北京\r\n'"
	//写入时使用带缓存的*Writer
	Writer:=bufio.NewWriter(file)
	for i:=0;i<5;i++{
		Writer.WriteString(str)
	}
	//因此writer 带缓存到内存的,因此要同步磁盘
	Writer.Flush()//同步到磁盘
	//
}

  方式2

package main

import (
	"bufio"
	"fmt"
	"os"
	"io"
	//"strings"
)
func main(){

	//1.打开文件
	file,err:= os.OpenFile("d:/abc.txt", os.O_RDWR|os.O_APPEND,0666)
	if err!=nil{
		fmt.Printf("open file %v\n",err)
		return
	}
	defer file.Close()
	read:=bufio.NewReader(file)
	for {
		str,err:=read.ReadString('\n') //读到换行符结束一行
		if err == io.EOF{ //io.EOF,表示文件结尾
			break
		}
	   fmt.Print(str) 
	}
	//准备写入内容
	str := "'hello,北京\r\n'"
	//写入时使用带缓存的*Writer
	Writer:=bufio.NewWriter(file)
	for i:=0;i<5;i++{
		Writer.WriteString(str)
	}
	//因此writer 带缓存到内存的,因此要同步磁盘
	Writer.Flush()//同步到磁盘
	//
}

  从一个文件读取内容到另一个文件

package main

import (
	//"bufio"
	"fmt"
	//"io"
	//"io/ioutil"

	//"io/ioutil"
	"os"
)
func main(){
	//将d:/adc.txt文件内容导入d:/kkk.txt
	//首先将d:/adc.txt 内容读取到内存
	//2将读取到内容写入kkk.txt
	filepath1:= "D:/abc.txt"
	filepath2:= "D:/kkk.txt"
	data,err :=os.ReadFile(filepath1)
	if err !=nil{
		fmt.Println("错误:",err)
	}
	err =os.WriteFile(filepath2,data,0666)
	if err!=nil{
		fmt.Println("writeFile err=",err)
	}
}

  判断文件是否存在

Golang 判断文件或文件夹是否存在的方法为使用os.Stat()函数返回的错误值进行判断:

1)如果返回错误为nil,说明文件或文件存在

2)如果返回错误类型使用os.lsNotExist()判断为true。说明文件夹或文件不存在

3)如果返回的错误为其他类型,则不确定是否存在

func Stat(name string) (fi FileInfo, err error)

 Stat返回一个描述name指定的文件对象的FileInfo。如果指定的文件对象是一个符号链接,返回的FileInfo描述该符号链接指向的文件的信息,本函数会尝试跳转该链接。如果出错,返回的错误值为*PathError类型。

文件拷贝

func Copy(dst Writer, src Reader) (written int64, err error)
将src的数据拷贝到dst,直到在src上到达EOF或发生错误。返回拷贝的字节数和遇到的第一个错误。

对成功的调用,返回值err为nil而非EOF,因为Copy定义为从src读取直到EOF,它不会将读取到EOF视为应报告的错误。如果src实现了WriterTo接口,本函数会调用src.WriteTo(dst)进行拷贝;否则如果dst实现了ReaderFrom接口,本函数会调用dst.ReadFrom(src)进行拷贝。

  示例拷贝文件

package main

import (
	//"bufio"
	"bufio"
	"fmt"
	"io"

	//"internal/syscall/windows"
	//"io"
	//"io/ioutil"

	//"io/ioutil"
	"os"
)
func CopyFile(detFileName string,srcFileName string)(written int64,err error){
	srcFile,err:= os.Open(srcFileName)
	if err !=nil{
		fmt.Printf("源文件异常:%v\n",err)
	}
	defer srcFile.Close()
	//通过文件句柄
	reade :=bufio.NewReader(srcFile)
	detFile,err:=os.OpenFile(detFileName,os.O_WRONLY|os.O_CREATE,0666)
	if err !=nil{
		fmt.Printf("open file err=%v\n",err)
	}
	defer detFile.Close()
	// 通过disFile,获取Write
	writer:= bufio.NewWriter(detFile)
	return io.Copy(writer,reade)

}
func main(){
	//将"C:/Users/尘曦/Desktop/2x.jpg"拷贝到D:/abc.jpg
	//1
     src:="C:/Users/尘曦/Desktop/2x.jpg"
	 dst:="d:/1.jpg"
	_,err:=CopyFile(dst,src)
	if err == nil{
		fmt.Println("拷贝完成")
	}else{
		fmt.Println("拷贝失败")
	}
}
//执行结果
//PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\deom10\mian.go
//拷贝完成

  统计不同类型的英文、数字、空格和其他字符数量

package main

import (
	"bufio"
	"fmt"
	"io"
	//"math/rand"
	"os"
	"unicode"
)

//定义一个结构体用于保存结果
type CharCount struct{
	CharCount  int //记录英文个数
	NumCount int //记录数字个数
	SpaceCount int //记录空格个数
	OtherCount int //记录其他字符
	Chr int
}
func main(){
	//思路: 打开一个文件,创一个Reader
	//每读取一行,就去统计该行有多少个英文、数字、空格和其他字符
	//然后将结果保存到一个结构体中
	fileName:="D:/abc.txt"
	file,err := os.Open(fileName)
	if err !=nil{
		fmt.Println("open file err=",err)//
		return
	}
	defer file.Close()
	//定义CharCount 实力
	var count CharCount 
	//创建一个reader
	reader:=bufio.NewReader(file)
	for {
		str,err:=reader.ReadString('\n')

	
		for _,r:=range str{
		 
		switch {
		case unicode.Is(unicode.Han, r): //匹配中文
			count.Chr++
		case (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z'):
			count.CharCount++
		case r >= '0' && r <= '9':
			count.NumCount++
		case r == ' ' || r == '\t':
			count.SpaceCount++
		default:
			count.OtherCount++
	    }
		 }
		if err == io.EOF{
			break
		}
		}
	fmt.Printf("字符个数%v,数字个数%v,空格个数%v,其他字符个数%v,中文%v",
			count.CharCount, count.NumCount, count.SpaceCount,count.OtherCount,count.Chr)
}

  命令行参数

希望能够获取到命令行输入的各种参数,该如何处理

基本介绍os.Args是一个string的切片,用来存储所有的命令行参数

package main
import (
	"fmt"
	"os"
)
func  main(){
	fmt.Println("命令行的参数个数有",len(os.Args))
	//遍历这个切片
	for i,v:= range os.Args{
		fmt.Printf("agrs[%v]=%v\n",i,v)
	}
}
// 执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go build -o chapter15\deom12\test.exe chapter15\deom12\mian.go
// PS D:\golang\goproject\src\src01\go_code\src>  chapter15\deom12\test.exe tom  123 d:/1.txt 909
// 命令行的参数个数有 5
// agrs[0]=D:\golang\goproject\src\src01\go_code\src\chapter15\deom12\test.exe
// agrs[1]=tom
// agrs[2]=123
// agrs[3]=d:/1.txt
// agrs[4]=909

  flag 包解析命令行参数

说明:前面的方式是比较原生的方式,对解析参数不是特别的方便,特别是带参数形式的命令行

例如:cmd>main.exe -f c:/aaa.txt -p200 -u root 这样的形式命令行,go 设计者给我们提供flag包,可以方便的解析命令行参数,而且参数顺序可以随意

func (*FlagSet) IntVar

func (f *FlagSet) IntVar(p *int, name string, value int, usage string)
IntVar用指定的名称、默认值、使用信息注册一个int类型flag,并将flag的值保存到p指向的变量。

 

func Parse

func Parse()
从os.Args[1:]中解析注册的flag。必须在所有flag都注册好而未访问其值时执行。未注册却使用flag -help时,会返回ErrHelp。

  shil

package main
import (
	"fmt"
	//"os"
	"flag"
)
func  main(){
//定义几个变量,用于接收
	var  user string
	var  pwd string
	var  host string
	var  prot int
	//&user用于接收用户命令行输入的-u,后面参数值
	//u 就是-u 这个参数
	//"" 表示默认值
	//"用户名默认为空" 对参数说明
	flag.StringVar(&user,"u","","用户名默认为空")
	flag.StringVar(&pwd,"pwd","","密码默认为空")
	flag.StringVar(&host,"h","localhost","主机默认为localhost")
	flag.IntVar(&prot,"port",3306,"默认3306")
	//这里有一个非常重要操作,转换,必须调用方法
	flag.Parse()
	fmt.Printf("user=%v;pwd=%v;host=%v;prot=%v\n",user,pwd,host,prot)
	
}
// 执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\deom13\mian.go -u chenxi -pwd 123.com -h 127.0.0.1 -port 3306         
// user=chenxi;pwd=123.com;host=127.0.0.1;prot=3306

  JSON 介绍

json 是一种轻量级的数据,易于人阅读编写,同时也易于机器解析和生成。json 是在2001年开始推广使用的数据格式,目前已经成为主流的数据格式;json易于机器解析和生成,并有效地提升网络传输效率,通常程序在网络传输时会优先将数据(结构体、map等)序列化成json字符串,到接收方得到json字符串时,在反序列化恢复成原来的数据类型(结构体、map等)。这种方式已然成为各个语言的标准

image

json 数据格式说明

在js 语言中,一切接对象,因此,任何的数据类型都可以通过JSON来表示,如字符串、数字、对象、数组、map、结构体等

JSON键值对是用来保存数据一种形式方法

键/值对组合中的键名写在前面并用双引号“”包裹,使用冒号:分隔然后紧接着值:

例如

{"firstName":"json"}
{"name":"tom","age":"18","address":["北京","上海"]}
[{"name":"tom","age":"18","address":["北京","上海"]},
{"name":"mary","age":"28","address":["北京","上海"]}]

  json数据线上解析网址:https://www.json.cn/

json 的序列化

介绍

JSON序列化是指,将key-value 结构的数据类型(如结构体,map,切片)序列化成JSON字符串操作

package main

import (
	"encoding/json"
	"fmt"
	//"strings"
)
type Monster struct{
	Name string
	Age int
	Birthday string
	Sal float64
	Skill string
}
func tsetStruct() {
	//
	monster:=Monster{
		Name: "牛魔王",
		Age: 2500,
		Birthday: "1年1月16日",
		Sal: 8900,
		Skill: "牛魔拳",
	}
	//将moster序列化
	data,err:=json.Marshal(&monster)
	if err !=nil{
		fmt.Println("序列号失败",err)
		return
	}
	//输出系列化后结果
	fmt.Printf("序列化后数据=%v\n",string(data))
	
}
func testMap(){
	//定义一个map
	var a map[string]interface{}
	//
	a= make(map[string]interface{})
	a["name"]="红孩儿"
	a["age"]=30
	a["adderss"]="火云洞"
	//将map 序列号
	data,err:=json.Marshal(a)
	if err !=nil{
		fmt.Println("序列号失败",err)
		return
	}
	//输出系列化后结果
	fmt.Printf("序列化后数据=%v\n",string(data))

}
func testSlice(){
	var slice []map[string]interface{}
	//slice=append(slice, map[string]interface{}{"名字":"雷锋"})
	var m1 map[string]interface{}
	m1= make(map[string]interface{})
	m1["name"]="jack"
	m1["age"]= 6
	m1["address"]="北京"
	slice = append(slice, m1)
	var m2 map[string]interface{}
	m2=make(map[string]interface{})
	m2["Name"]="小龙"
	m2["age"]=7
	m2["address"]="上海"
	slice=append(slice, m2)
	data,err:=json.Marshal(slice)
	if err !=nil{
		fmt.Println("序列号失败",err)
		return
	}
	//输出系列化后结果
	fmt.Printf("序列化后数据=%v\n",string(data))

}
//对基本数据类型序列号没有什么意义
func tsetInt(){
	var num1 float64=123.67
	data,err:=json.Marshal(num1)
	if err !=nil{
		fmt.Println("序列号失败",err)
		return
	}
	//输出系列化后结果
	fmt.Printf("序列化后数据=%v\n",string(data))

}
func main(){
	//演示将结构体、map、切片进行序列化
	tsetStruct()
	testMap()
	testSlice()
	tsetInt()
}
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\json\struct\mian.go
// 序列化后数据={"Name":"牛魔王","Age":2500,"Birthday":"1年1月16日","Sal":8900,"Skill":"牛魔拳"}
// 序列化后数据={"adderss":"火云洞","age":30,"name":"红孩儿"}
// 序列化后数据=[{"address":"北京","age":6,"name":"jack"},{"Name":"小龙","address":"上海","age":7}]
// 序列化后数据=123.67

  序列化时指定自定义结构体格式 tag `json:"name"` //tag 指定序列号后的字段格式;在定义结构体字段后指定

package main

import (
	"encoding/json"
	"fmt"
	//"strings"
)
type Monster struct{
	Name string `json:"name"` //tag 指定序列号后的字段格式
	Age int `json:"age"` //tag 指序列后的字段格式
	Birthday string
	Sal float64
	Skill string
}
func tsetStruct() {
	//
	monster:=Monster{
		Name: "牛魔王" ,
		Age: 2500 ,
		Birthday: "1年1月16日",
		Sal: 8900,
		Skill: "牛魔拳",
	}
	//将moster序列化
	data,err:=json.Marshal(&monster)
	if err !=nil{
		fmt.Println("序列号失败",err)
		return
	}
	//输出系列化后结果
	fmt.Printf("序列化后数据=%v\n",string(data))
	
}
func testMap(){
	//定义一个map
	var a map[string]interface{}
	//
	a= make(map[string]interface{})
	a["name"]="红孩儿"
	a["age"]=30
	a["adderss"]="火云洞"
	//将map 序列号
	data,err:=json.Marshal(a)
	if err !=nil{
		fmt.Println("序列号失败",err)
		return
	}
	//输出系列化后结果
	fmt.Printf("序列化后数据=%v\n",string(data))

}
func testSlice(){
	var slice []map[string]interface{}
	//slice=append(slice, map[string]interface{}{"名字":"雷锋"})
	var m1 map[string]interface{}
	m1= make(map[string]interface{})
	m1["name"]="jack"
	m1["age"]= 6
	m1["address"]="北京"
	slice = append(slice, m1)
	var m2 map[string]interface{}
	m2=make(map[string]interface{})
	m2["Name"]="小龙"
	m2["age"]=7
	m2["address"]="上海"
	slice=append(slice, m2)
	data,err:=json.Marshal(slice)
	if err !=nil{
		fmt.Println("序列号失败",err)
		return
	}
	//输出系列化后结果
	fmt.Printf("序列化后数据=%v\n",string(data))

}
//对基本数据类型序列号没有什么意义
func tsetInt(){
	var num1 float64=123.67
	data,err:=json.Marshal(num1)
	if err !=nil{
		fmt.Println("序列号失败",err)
		return
	}
	//输出系列化后结果
	fmt.Printf("序列化后数据=%v\n",string(data))

}
func main(){
	//演示将结构体、map、切片进行序列化
	tsetStruct()
	testMap()
	testSlice()
	tsetInt()
}
//执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\json\struct\mian.go
// 序列化后数据={"name":"牛魔王","age":2500,"Birthday":"1年1月16日","Sal":8900,"Skill":"牛魔拳"}
// 序列化后数据={"adderss":"火云洞","age":30,"name":"红孩儿"}
// 序列化后数据=[{"address":"北京","age":6,"name":"jack"},{"Name":"小龙","address":"上海","age":7}]
// 序列化后数据=123.67

  反序列化

JSON 反序列号是指,将JSON字符串反序列化成对应的数据类型(结构体、map、切片)的操作

package main
import (
	"fmt"
	"encoding/json"
)
type Monster struct{
	Name string `json:"name"` //tag 指定序列号后的字段格式
	Age int `json:"age"` //tag 指序列后的字段格式
	Birthday string
	Sal float64
	Skill string
}
//演示将JSON字符串,反序列化成struct
func unmarshalStruct(){
// 说明str 在项目开发中,是通过网络传输获取到的。。。或者读文件获取到的
	str:="{\"name\":\"牛魔王\",\"age\":2500,\"Birthday\":\"1年1月16日\",\"Sal\":8900,\"Skill\":\"牛魔拳\"}"
    var monster Monster
	//反序列化操作
	err:=json.Unmarshal([]byte(str),&monster)
	if err !=nil{
		fmt.Printf("Unmarshal err=%v\n",err)
	}
	fmt.Println(monster)

}
//演示将JSON字符串,反序列化成map
func unmarshalmap(){
	var a map[string]interface{}
	str := "{\"name\":\"牛魔王\",\"age\":2500,\"Birthday\":\"1年1月16日\",\"Sal\":8900,\"Skill\":\"牛魔拳\"}"
	//直接反序列化不需要make;因为make操作直接被封装在json.Unmarshal函数里了
	err:=json.Unmarshal([]byte(str),&a)
	if err !=nil{
		fmt.Printf("Unmarshal err=%v\n",err)
	}
	fmt.Println(a)

}
//将json 反序列切片
func unmarshalslice(){
	var slice []map[string]interface{}
	str := "[{\"address\":\"北京\",\"age\":6,\"name\":\"jack\"},{\"Name\":\"小龙\",\"address\":\"上海\",\"age\":7}]"
	// err:=json.Unmarshal([]byte(str),slice)
	// if err!=nil{
	// 	fmt.Printf("Unmarshal err=%v\n",err)
	// }
	err:=json.Unmarshal([]byte(str),&slice)
	if err !=nil{
		fmt.Printf("Unmarshal err=%v\n",err)
	}
	fmt.Println(slice)
}
func main(){
	unmarshalStruct()
	unmarshalmap()
	unmarshalslice()

}
// 执行结果
// PS D:\golang\goproject\src\src01\go_code\src> go run chapter15\unmarshal\main.go  
// {牛魔王 2500 1年1月16日 8900 牛魔拳}
// map[Birthday:1年1月16日 Sal:8900 Skill:牛魔拳 age:2500 name:牛魔王]
// [map[address:北京 age:6 name:jack] map[Name:小龙 address:上海 age:7]]

1)在反序列化一个字符串时,要确保反序列化数据类型和序列化前的数据一致(特别)

2)如果json字符串是通过网络程序或者文件读取则不需要再进行“”转义处理。

 

posted @ 2026-03-22 20:08  烟雨楼台,行云流水  阅读(2)  评论(0)    收藏  举报