目录
8.2、从文件中读取json转换为map,向文件中写 从map转换为json
一、IO包
Go语言中,为了方便开发者使用,将io操作封装在了如下几个包中
- io为IO原语提供基本的接口 例如 os相关内容中学过的 File中Reader和Writer
- io/ioutil封装了一些使用的IO函数
- fmt实现格式化IO,类似C中的printf和scanf
- bufio实现带缓冲IO
1.1、常用函数
io包所在地址
package main
import (
"fmt"
"io"
"log"
"os"
"strings"
)
func testCopy() {
//将file1拷贝到file2
reader := strings.NewReader("hello world")
_, err := io.Copy(os.Stdout, reader) //Copy(Writer,Reader),这里的copy是os.Stdout是标准输出,显示在控制台里面
if err != nil {
log.Fatal(err)
}
}
// copyBuffer
func copyBuffer() {
r1 := strings.NewReader("first reader\n")
r2 := strings.NewReader("second reader\n")
buf := make([]byte, 8)
// buf is used here... 借助缓冲区来copy,提高效率。之前是一个一个字节的copy
//使用copybuffer是一个缓冲区一个缓冲区的copy
if _, err := io.CopyBuffer(os.Stdout, r1, buf); err != nil {
log.Fatal(err)
}
// ... reused here also. No need to allocate an extra buffer.
if _, err := io.CopyBuffer(os.Stdout, r2, buf); err != nil {
log.Fatal(err)
}
}
// limitReader 限制copy的字节 输出是some,因为limitReader只限制读四个字节
func limitReader() {
r := strings.NewReader("some io.Reader stream to be read\n")
lr := io.LimitReader(r, 4)
if _, err := io.Copy(os.Stdout, lr); err != nil {
log.Fatal(err)
}
}
// MultiReader 一次性的读多个文件
func mutiReader() {
r1 := strings.NewReader("first reader ")
r2 := strings.NewReader("second reader ")
r3 := strings.NewReader("third reader\n")
r := io.MultiReader(r1, r2, r3)
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
}
}
// 一次性将文件copy到多个writer中
func mutiWriter() {
r := strings.NewReader("some io.Reader stream to be read\n")
var buf1, buf2 strings.Builder
w := io.MultiWriter(&buf1, &buf2)
if _, err := io.Copy(w, r); err != nil {
log.Fatal(err)
}
fmt.Print(buf1.String())
fmt.Print(buf2.String())
}
// Pipe既有输入又有输出 r是reader,w是writer。
func pipe() {
r, w := io.Pipe()
go func() {
fmt.Fprint(w, "some io.Reader stream to be read\n") //往writer里面写了一些内容
w.Close()
}()
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
//reader读出一些内容,显示在控制台中
}
}
/*
另外一些常用的函数
readAll--全都读出来
NewSectionReader(r,5,7) //只读reader中5-17索引这一部分
*/
func main() {
//reader := strings.NewReader("hello world")
//buf := make([]byte, 10)
//reader.Read(buf)
//println(string(buf))
testCopy()
copyBuffer()
limitReader()
mutiReader()
mutiWriter()
pipe()
}
1.2、ioutil包
封装一些实用的I/O函数
官方文档实例:
ioutil package - io/ioutil - Go Packages
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"strings"
)
func testReadAll() {
//读取字符串
r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.")
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", b)
//读取文件
f, err1 := os.Open("test1.txt") //file实现了reader
defer f.Close()
if err1 != nil {
b1, err2 := ioutil.ReadAll(f) //readAll里面要求传入的就是reader
if err2 != nil {
fmt.Printf("err2:%v\n", err2)
} else {
println(string(b1))
}
}
}
// 读目录
func testReadDir() {
fi, _ := ioutil.ReadDir(".") //遍历当前目录
for _, v := range fi {
fmt.Println(v.Name())
}
}
// 读文件
func testReadFile() {
b, _ := ioutil.ReadFile("test1.txt")
println(string(b))
}
// 写文件
func testWriteFile() {
ioutil.WriteFile("test2.txt", []byte("hello world"), 0664)
}
// 创建一个临时文件
func testTempFile() {
content := []byte("temporary file's content")
f, err := ioutil.TempFile("", "example") //第一个是dir,如果不指定的话,就在windows默认的临时目录下创建一个前缀是example的临时文件
if err != nil {
log.Fatal(err)
}
println(f.Name()) //C:\Users\QYC\AppData\Local\Temp\example3418719847
defer os.Remove(f.Name()) //最后记得删除
if _, err := f.Write(content); err != nil {
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}
func main() {
testReadAll()
testReadDir()
testReadFile()
testWriteFile()
testTempFile()
}
1.3、bufio
bufio包实现了有缓冲的IO。包装了一个io.Reader或者io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本IO的帮助函数的都西昂
没有使用bufio之前是从磁盘中读一个字节写一个字节,需要很多次的磁盘读写次数。有了bufio之后,是先读到缓冲区中(默认缓冲区大小是4096),再从缓冲区中读,这样磁盘读写次数减少
bufio.NewReader(f) |
将原来的reader进行封装,创建了一个新的reader,用于将内容放在缓冲区里 |
r2 := bufio.NewReader(f) p := make([]byte, 10) r2.Read(p) |
每次读取一个缓冲区大小的字符串,n表示此次读取的个数 |
p := bufio.NewReader(f) p.UnreadByte() |
吐出来一个字节---退回一个字节 |
bf := bufio.NewReader(s) bf.ReadSlice、 ReadBytes、 ReadString |
以一个符号为分割,读取第一个切片 |
bf := bufio.NewReader(s) l, isPrefix, _ := bf.ReadLine() |
读取一行 以\n为行结束的标志 |
bf.WriteTo(file) |
写到一个地方去,可以是缓冲区,也可以是文件等 |
bufio.NewWriter(f) |
写在缓冲区里,再从缓冲区里一下子写到文件里面 |
bufio.NewReadWriter(br, bw) |
既有读的功能又有写的功能 |
bs := bufio.NewScanner(s) bs.Split(bufio.ScanWords) |
bufio.ScanBytes以字符为单位分割 bufio.ScanRunes以汉字、日文等为单位分割bufio.ScanWords以单词为单位分割 |
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
/*
bufio
*/
func testNewReader() {
//r := strings.NewReader("hello zxx")
//也可以读一个文件
f, _ := os.Open("test1.txt")
defer f.Close()
r2 := bufio.NewReader(f) //将原来的reader进行封装,创建了一个新的reader
s, _ := r2.ReadString('\n') //读出之后以\n作为结尾
println(s)
}
func testRead() {
f, _ := os.Open("test1.txt")
defer f.Close()
r2 := bufio.NewReader(f)
p := make([]byte, 10) //开辟一个10个大小的缓冲区
for {
n, err := r2.Read(p) //每次读取一个缓冲区大小的字符串,n表示此次读取的个数
if err == io.EOF {
break
} else {
println(string(p[0:n]))
}
}
}
// 吐出来一个字节
func testUnreadByte() {
f, _ := os.Open("test1.txt") //hello!!and love the world and love QYC
defer f.Close()
p := bufio.NewReader(f)
c, _ := p.ReadByte()
fmt.Printf("%c\n", c) //h
c, _ = p.ReadByte()
fmt.Printf("%c\n", c) //e
p.UnreadByte() //吐出来一个字节---退回一个字节
c, _ = p.ReadByte()
fmt.Printf("%c\n", c) //按理来说应该读l,但是吐出来一个字节。所以还是读e
}
// 读取切片 ReadBytes、ReadString也是同样的道理
func testReadSlice() {
s := strings.NewReader("ABC,DEF,HHY")
bf := bufio.NewReader(s)
w, _ := bf.ReadSlice(',') //以逗号为分割,读取第一个切片"ABC,"
fmt.Printf("%q\n", w)
w, _ = bf.ReadSlice(',') //"DEF,"
fmt.Printf("%q\n", w)
w, _ = bf.ReadSlice(',') //"HHY"
fmt.Printf("%q\n", w)
}
// 读取一行 以\n为行结束的标志
func testReadLine() {
s := strings.NewReader("ABC\nDEF\nHHY")
bf := bufio.NewReader(s)
l, isPrefix, _ := bf.ReadLine()
fmt.Printf("%q %v\n", l, isPrefix) //"ABC" false 如果一行超过缓冲区大小(4096 就显示true,表示输出的是这一行的前缀)
l, isPrefix, _ = bf.ReadLine()
fmt.Printf("%q %v\n", l, isPrefix) //"DEF" false
l, isPrefix, _ = bf.ReadLine()
fmt.Printf("%q %v\n", l, isPrefix) //"HHY" false
}
// WriteTo写到一个地方去,可以是缓冲区,也可以是文件等
func testWriteTo() {
s := strings.NewReader("ABC\nDEF\nHHY")
bf := bufio.NewReader(s)
file, _ := os.OpenFile("test1.txt", os.O_RDWR, 0777) //写道文件中必须是可读可写
bf.WriteTo(file)
defer file.Close()
}
// newWriter,写在缓冲区里,再从缓冲区里一下子写到文件里面
func testNewWriter() {
f, _ := os.OpenFile("test1.txt", os.O_RDWR, 0777)
defer f.Close() //一定要记得关,否则写不进去
w := bufio.NewWriter(f) //file里面既封装了writer又封装了reader。所以可以当成writer也可以当成reader来使用
w.WriteString("hello world") //假如是视频等大文件,这样会更高效
w.Flush() //一定要记得刷新缓冲区,否则写不进去
}
// newReadWriter 既有读的功能又有写的功能
func testNewReadWriter() {
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
s := strings.NewReader("123")
br := bufio.NewReader(s)
rw := bufio.NewReadWriter(br, bw) //rw就是可读可写的了
p, _ := rw.ReadString(' ')
println(string(p))
rw.WriteString("123567")
rw.Flush()
fmt.Println(b)
}
// NewScanner bufio.ScanBytes以字符为单位分割 bufio.ScanRunes()以汉字、日文等为单位分割
func testNewScanner() {
s := strings.NewReader("ABC DFR GTH YYU")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanWords) //一个word一个word的进行打印--以空格作为分隔符进行分割
for bs.Scan() {
fmt.Println(bs.Text())
}
}
func main() {
testRead()
testUnreadByte()
testReadSlice()
testReadLine()
testWriteTo()
//写相关
testNewReadWriter()
testNewWriter()
//scan相关
testNewScanner()
}
二、log
golang里面内置了log包,实现简单的日志服务。通过调用log包的函数,可以实现简单的日志打印功能
2.1、log使用
package main
import "log"
func test1() {
log.Print("my log") //2023/10/26 21:39:57 my log
log.Printf("my lod %d", 100) //格式化输出 2023/10/26 21:42:36 my lod 100
name := "tom"
age := 20
log.Println(name, " ", age) //2023/10/26 21:42:36 tom 20
}
func test2() {
defer println("panic 结束后再执行")
log.Print("my log")
log.Panic("my log")
println("end...")
}
/*
panic之后会引出一个panic错误,之后的代码都不再执行了。除了defer。defer还是会照常执行
panic其他的方法和print一样
2023/10/26 21:45:44 my log
2023/10/26 21:45:44 my log
panic 结束后再执行
panic: my log
goroutine 1 [running]:
log.Panic({0xc00007dee8?, 0x0?, 0x1f4e1b1c2b8?})
D:/go/src/log/log.go:432 +0x5a
main.test2()
D:/zxx/go_code/src/study/test_io.go:16 +0xc9
main.main()
D:/zxx/go_code/src/study/test_io.go:24 +0xf
Process finished with the exit code 2
*/
func test3() {
defer println("defer...")
log.Print("my log")
log.Fatal("fatal...")
println("end...")
}
/*
fatal也会引出错误,但终端并不显示。fatal之后任何的代码都不执行了,包括defer
fatal中也有fatalln和fatalf,和print一样
2023/10/26 21:47:51 my log
2023/10/26 21:47:51 fatal...
*/
func main() {
//test1()
//test2()
test3()
}
2.2、log的配置
方法一:比较复杂
package main
import (
"log"
"os"
)
// 构造函数 先于main函数执行
func init() {
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) //设置日志显示日期、时间、短文件名
log.SetPrefix("MY LOG:") //设置前缀
f, err := os.OpenFile("test1.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0664)
if err != nil {
log.Fatal("日志文件错误")
}
log.SetOutput(f) //将日志写入到文件中
}
func main() {
i := log.Flags()
println(i)
log.Print("my log")
}
方法二:比较简单
New一个log。一股脑地设置输出位置、flag等等
package main
import (
"log"
"os"
)
var logger *log.Logger //要记得这里
func init() {
f, err := os.OpenFile("test1.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0664)
if err != nil {
log.Fatal("日志文件错误")
}
/*
下面这句话就可以直接配置了
*/
logger = log.New(f, "My LOG", log.Lshortfile|log.Ltime|log.Ldate)
}
func main() {
logger.Print("my log") //注意这里不是log了
}
三、builtin
这个包提供了一些类型声明、变量和常量声明,还有一些便利函数。这个包不需要导入,这些变量和函数都可以直接使用
builtin package - builtin - Go Packages
常用函数
3.1 append
3.2、new和make
new和make的区别
package main
import "fmt"
func testNew() {
b := new(bool)
fmt.Printf("b:%T\n", b) //b:*bool 可以看出new出来的是指针类型
fmt.Printf("b:%v\n", *b) //b:false
//同理其他类型 int的初值是0 string的初值是空
}
func testMake() {
var p *[]int = new([]int)
fmt.Printf("p:%v\n", p) //p:&[] new出来的是一个指针
v := make([]int, 15, 20)
fmt.Printf("v:%v\n", v) //v:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]//make出来的是本身,且都被初始化过了
v = make([]int, 10, 20)
fmt.Printf("v:%v\n", v) //v:[0 0 0 0 0 0 0 0 0 0]
}
func main() {
testNew()
testMake()
}
补充:切片的长度是切片中元素的数量,容量是底层数组的长度。例如容量为100,长度为10.表示这个切片底层数组可以容纳100个元素,现在有10个元素
四、bytes
bytes包提供了对字节切片进行读写操作的一系列函数,字节切片处理的函数比较多,分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和切片处理函数
字节切片相当于string
4.1常用函数
Contanis(b,b1) |
b是否包含b1 |
Repeat(b,num) |
将字节切片b重复num次 |
Count(s,sep1) |
统计sep1在b中出现了几次 |
bytes.Replace(s, old, news, num) |
/将s中的old用news替换num次。num=-1,代表全部替换 |
testRenus() |
转换成真正意义上的方块字 |
bytes.Join(s2, sep5) |
s2是一个二维切片,将二维切片中的每一个切片数组用sep5连接起来 |
package main
import (
"bytes"
"fmt"
)
/*
标准库字节切片-bytes
*/
func testTrans() {
var i int = 100
var b byte = 10
b = byte(i) //把int类型的i强制转换为byte类型的b
println(b)
i = int(b) //把byte类型的b强制转换为int类型的i
println(i)
var s string = "hello world"
b1 := []byte{1, 2, 3}
s = string(b1) //字节切片转换为string
fmt.Printf("%v\n", s)
b1 = []byte(s) //string类型转换为字节切片
println(b1)
}
// Contanis(b,b1) b是否包含b1
func testContanis() {
s := "zxx.com"
b := []byte(s) //将string转换为字节切片
fmt.Printf("s:%s\n", s)
fmt.Printf("s:%s\n", b)
b1 := []byte("zxx")
b2 := []byte("Zxx")
c1 := bytes.Contains(b, b1) //看b里面是否包含b1
fmt.Printf("c1:%t\n", c1) //c1:true b里面包括b1
c2 := bytes.Contains(b, b2)
fmt.Printf("c2:%t\n", c2) //c2:false b里面不包括b2
}
// Repeat(b,num)将字节切片b重复num次
func testRepeat() {
b := []byte("hi")
fmt.Println(string(bytes.Repeat(b, 1))) //hi
fmt.Println(string(bytes.Repeat(b, 3))) //hihihi
}
// Count(s,sep1) 统计sep1在b中出现了几次
func testCont() {
s := []byte("hellooooooooooooooo")
sep1 := []byte("h")
sep2 := []byte("lo")
sep3 := []byte("o")
fmt.Println(bytes.Count(s, sep1)) //1
fmt.Println(bytes.Count(s, sep3)) //15
fmt.Println(bytes.Count(s, sep2)) //1
}
// bytes.Replace(s, old, news, num) //将s中的old用news替换num次。num=-1,代表全部替换
func testReplace() {
s := []byte("hello world")
old := []byte("o")
news := []byte("ee")
fmt.Println(string(bytes.Replace(s, old, news, 0))) //hello world
fmt.Println(string(bytes.Replace(s, old, news, 1))) //hellee world
fmt.Println(string(bytes.Replace(s, old, news, 2))) //hellee weerld
fmt.Println(string(bytes.Replace(s, old, news, -1))) //hellee weerld
}
// testRenus() 转换成真正意义上的方块字
func testRnues() {
s := []byte("你好世界")
r := bytes.Runes(s)
fmt.Println("转换前字符串的长度:", len(s)) //12 转换前是字符切片的长度,一个汉字代表3个字节
fmt.Println("转换后字符串的长度:", len(r)) //4 转换后就是汉字的长度了 有几个汉字就多长
}
// bytes.Join(s2, sep5) s2是一个二维切片,将二维切片中的每一个切片数组用sep5连接起来
func testJoin() {
//join
s2 := [][]byte{[]byte("你好"), []byte("世界")} //二维切片
sep4 := []byte(",")
println(string(bytes.Join(s2, sep4))) //你好,世界
sep5 := []byte("#")
println(string(bytes.Join(s2, sep5))) //你好#世界
}
func main() {
testTrans()
testContanis()
testRepeat()
testCont()
testReplace()
testRnues()
testJoin()
}
4.2、Reader类型
package main
import (
"bytes"
"fmt"
)
/*
标准库字节切片-bytes
*/
func testReader() {
data := "12345678"
//通过[]byte创建reader
re := bytes.NewReader([]byte(data))
//返回未读取部分的长度
fmt.Println("re len:", re.Len()) //re len: 8
//返回底层数据长度
fmt.Println("re size:", re.Size()) //re size: 8
println("...............")
buf := make([]byte, 2)
for {
n, err := re.Read(buf)
if err != nil {
break
}
fmt.Println(string(buf[:n]))
}
/*
12
34
56
78
*/
println("...............")
//设置偏移量,因为上面的操作已经修改了读取位置等信息
re.Seek(0, 0) //重新回到文件头
for {
//一个字节一个字节的读
b, err := re.ReadByte()
if err != nil {
break
}
fmt.Println(string(b))
}
/*
1
2
3
4
5
6
7
8
*/
println("....................")
re.Seek(0, 0)
off := int64(0)
for {
//指定读的位置
n, err := re.ReadAt(buf, off)
if err != nil {
break
}
off += int64(n)
fmt.Println(off, string(buf[:n]))
}
/*
2 12
4 34
6 56
8 78
*/
}
func main() {
testReader()
}
4.3 buffer
package main
import (
"bytes"
"fmt"
"io"
)
/*
标准库字节切片-bytes
*/
func testBuffer() {
//buffer的构建方法
var b bytes.Buffer //构建一个buffer类型
fmt.Printf("b:%v\n", b) //b:{[] 0 0} []表示缓冲区,现在缓冲区为空,0表示偏移量,最后一个0表示最后读取到的位置
fmt.Printf("b1:%T\n", b) //b1:bytes.Buffer
var b1 = bytes.NewBufferString("hello") //从一个string变量,构建一个Buffer
fmt.Printf("b1:%v\n", b1) //b1:hello
fmt.Printf("b1:%T\n", b1) //b1:*bytes.Buffer
}
// 往buffer中写入
func testWriter() {
var b bytes.Buffer
n, _ := b.WriteString("hello")
fmt.Printf("n:%v\n", n) //5
fmt.Printf("b:%s\n", b.Bytes()) //b:hello
}
// 从buffer中读取数据到指定容器
func testRead() {
var b = bytes.NewBufferString("hello world")
b1 := make([]byte, 2)
for {
n, err := b.Read(b1)
if err == io.EOF {
break
}
fmt.Printf("n:%v\n", n) //5
fmt.Printf("b:%s\n", b1[:n])
}
}
func main() {
testBuffer()
testWriter()
testRead()
}
五、errors
package main
import (
"errors"
)
/*
标准库字节切片-error
*/
//创建一个错误
func check(s string) (string, error) {
if s == "" {
err := errors.New("字符串不能为空")
return "", err
} else {
return s, nil
}
}
//
func main() {
s, err := check("")
if err != nil {
println(err.Error())
} else {
println(s)
}
}
六、sort包
6.1 普通类型
直接使用方法即可
package main
import (
"fmt"
"sort"
)
/*
标准库sort--排序
*/
func main() {
s := []int{2, 4, 1, 3}
sort.Ints(s)
fmt.Printf("s:%v\n", s) //s:[1 2 3 4]
}
6.2 自定义类型
自定义类型使用sort排序,需要自己重写三个方法,分别是len、swap、less
package main
import (
"fmt"
"sort"
)
/*
标准库sort--排序
*/
type NewInts []uint //创建一个新类型
func (n NewInts) Len() int {
return len(n)
}
func (n NewInts) Less(i, j int) bool {
fmt.Println(i, j, n[i] < n[j], n)
return n[i] < n[j]
}
func (n NewInts) Swap(i, j int) {
n[i], n[j] = n[j], n[i]
}
func main() {
n := []uint{1, 2, 3}
sort.Sort(NewInts(n))
fmt.Println(n)
}
6.3 复杂结构
6.3.1、二位切片 [][]int
6.3.2 []map[string]int
6.3.3 自定义结构体
七、time
7.1、基本使用
import (
"fmt"
"time"
)
/*
标准库sort--time
*/
func test1() {
now := time.Now() //获取当前时间
fmt.Printf("t:%T\n", now) //time.Time
fmt.Printf("t:%v\n", now) //2023-10-27 16:06:14.2869442 +0800 CST m=+0.006859101
//标准输出时间
year := now.Year()
month := now.Month()
day := now.Day()
hour := now.Hour()
minute := now.Minute()
second := now.Second()
fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
//2023-10-27 16:11:27
// %02d表示输出int类型。长度为2,位数不够的话前面补0
}
func main() {
test1()
}
7.2、时间戳
在编程中对于时间戳的应用也十分广泛,例如在web开发中做cookies的有效期,接口加密,Redis中的key有效期等等。
时间戳是自从1970年1月1日八点到当前时间的总毫秒数,也被称为Unix时间戳
时间戳转换为普通的时间格式
操作时间
ADD
SUB
Equal
Before
After
定时器
7.3、时间格式化
7.4、解析字符串格式的时间
func test4() {
now := time.Now()
fmt.Println(now)
//加载时区
location, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
fmt.Println(err)
return
}
//按照指定时区和指定格式解析字符串时间
timeObj, err := time.ParseInLocation("2006/01/02 15:04:05", "2023/10/27 16:35:02", location)
//timeObj就是一个时间类型了 包括year、Mouth等属性
if err != nil {
fmt.Println(err)
return
}
fmt.Println(timeObj) //2023-10-27 16:35:02 +0800 CST
fmt.Println(timeObj.Sub(now)) //-1m38.8951129s
fmt.Println(timeObj.Year()) //2023
}
八、json
这个包可以实现json的编码和解码,就是将json字符串转换为struct,或者将struct转换为json
核心的两个函数
在golang里面interface{}表示任意类型都可以接受
两个核心结构体
8.1、结构体和json的相互转化
Marshal和Unmarshal
package main
import (
"encoding/json"
"fmt"
)
/*
标准库sort--json
*/
type Person struct {
Name string
Age int
Email string
}
// 结构体转换为json json.Marshal(p)
func test1() {
p := Person{
Name: "tom",
Age: 20,
Email: "wddee",
}
b, _ := json.Marshal(p) //b是一个字符切片
println(string(b)) //{"Name":"tom","Age":20,"Email":"wddee"} 成功转换成了json
}
// json转换为结构体 json.Unmarshal
func test2() {
bytes := []byte("{\"Name\":\"tom\",\"Age\":20,\"Email\":\"wddee\"}")
var p Person
json.Unmarshal(bytes, &p) //把字节切片转换成了person结构体p
fmt.Printf("%v\n", p) //{tom 20 wddee}
}
func test3() {
b := []byte(`{"Name":"tom","Age":20,"Email":"wddee","Parents":["big tom","kite"]}`)
var f map[string]interface{}
json.Unmarshal(b, &f)
fmt.Printf("%v\n", f) //map[Age:20 Email:wddee Name:tom Parents:[big tom kite]]
for k, v := range f {
fmt.Printf("k:%v\n", k)
fmt.Printf("v:%v\n", v)
}
}
//
func main() {
test2()
test3()
}
8.2、从文件中读取json转换为map,向文件中写 从map转换为json
package main
import (
"encoding/json"
"fmt"
"os"
)
/*
标准库sort--json
*/
//从文件中读
func test4() {
f, _ := os.Open("test1.txt")
defer f.Close()
decoder := json.NewDecoder(f)
for {
var v map[string]interface{} //key是string。value是任意类型
if err := decoder.Decode(&v); err != nil {
return
}
fmt.Printf("%v\n", v)
}
}
//向文件中写
func test5() {
p := Person{
Name: "tom",
Age: 20,
Email: "wddee",
}
f, _ := os.OpenFile("test1.txt", os.O_WRONLY, 0777)
e := json.NewEncoder(f) //创建一个解码器
e.Encode(p) //解码
}
func main() {
//test2()
//test3()
test4()
test5()
}
九、XML
xml包实现xml解析
核心的两个函数
两个核心结构体
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
)
/*
标准库sort--json
*/
type Person struct {
XMLName xml.Name `xml:"person"`
Name string `xml:"name"`
Age int `xml:"age"`
Email string `xml:"email"`
}
// struct转化为xml
func test1() {
p := Person{
Name: "tom",
Age: 20,
Email: "wddee",
}
b, _ := xml.MarshalIndent(p, " ", " ") //缩进-让格式更好看
fmt.Printf("%v\n", string(b))
}
/*
<person>
<name>tom</name>
<age>20</age>
<email>wddee</email>
</person>
*/
// xml转化为struct
func test2() {
s := `
<person>
<name>tom</name>
<age>20</age>
<email>wddee</email>
</person>
`
b := []byte(s)
var per Person //定义一个接受对象的变量
xml.Unmarshal(b, &per)
fmt.Printf("%v\n", per)
}
/*
{
{ person} tom 20 wddee}
*/
// 从文件中读出来再转换为对象
func test3() {
b, _ := ioutil.ReadFile("test1.txt") //返回的b是一个字节切片
var per Person //定义一个接受对象的变量
err := xml.Unmarshal(b, &per)
if err != nil {
return
}
fmt.Printf("%v\n", per)
}
// 把结构体向文件中写 要用到一个Encoder
func test4() {
p := Person{
Name: "tom",
Age: 20,
Email: "wddee",
}
f, _ := os.OpenFile("test1.txt", os.O_WRONLY, 0777)
defer f.Close()
e := xml.NewEncoder(f)
e.Encode(p)
}
func main() {
test1()
test2()
test3()
test4()
}
十、math
10.1、常量
10.2、常用函数
- Abs(x float64) float64:返回x的绝对值。
- Ceil(x float64) float64:返回不小于x的最小整数值。
- Cos(x float64) float64:返回x的余弦值(x以弧度为单位)。
- Exp(x float64) float64:返回自然指数e的x次幂。
- Floor(x float64) float64:返回不大于x的最大整数值。
- Log(x float64) float64:返回x的自然对数。
- Max(x, y float64) float64:返回x和y中的最大值。
- Min(x, y float64) float64:返回x和y中的最小值。
- Mod(x, y float64) float64:返回x除以y的余数。
- Pow(x, y float64) float64:返回x的y次幂。
- Round(x float64) float64:返回四舍五入到最接近的整数值。
- Sin(x float64) float64:返回x的正弦值(x以弧度为单位)。
- Sqrt(x float64) float64:返回x的平方根。
- Tan(x float64) float64:返回x的正切值(x以弧度为单位)。
- 除此之外,math 包还包括一些常量,如:
- math.E:自然常数e。
- math.Pi:圆周率π。
- math.Sqrt2:2的平方根。
- math.SqrtE:自然常数e的平方根。
- math.SqrtPi:圆周率π的平方根。
- math.Ln2:2的自然对数。
- math.Log2E:以2为底的自然对数e的倒数。
- math.Log10E:以10为底的自然对数e的倒数。
- math.MaxFloat64:float64类型能够表示的最大值。
- math.SmallestNonzeroFloat64:float64类型中能够表示的最小非零值。
10.3 随机数
package main
import (
"math/rand"
"time"
)
/*
标准库sort--math
*/
func init() {
//rand.Seed(1) //设置种子--如果是一个固定的数,那么每次随即出来的结果都一样
//所以一般设置为当前的时间戳,就不会一样了
rand.Seed(time.Now().UnixMicro())
}
func main() {
//随机数
i := rand.Int() //i就是一个随机数
println(i)
//指定一个范围
intn := rand.Intn(100) //生成100以内的随机数
println(intn)
}
十一、文件读写整理
在Go语言中,用于读写操作的常用包包括io
、os
、bytes
和bufio
,而哪个包最常用取决于你的具体需求和使用场景。每个包都有其特定的用途和优势:
-
io包:
io
包提供了一组通用的接口和函数,用于处理输入和输出操作。它定义了Reader
和Writer
接口,允许你使用通用的方式进行数据读取和写入。这些接口和函数通常用于抽象不同的数据源和目标,因此在编写通用的、可扩展的代码时非常有用。io
包是Go中读写操作的基础。 -
os包:
os
包是操作系统的封装,提供了访问文件系统的功能。它包含文件的打开、创建、删除等函数。如果你需要直接操作文件、目录和文件属性,os
包通常是首选。它的函数可以用于文件的打开、读取、写入和关闭,以及文件操作相关的权限和属性设置。 -
bytes包:
bytes
包提供了对字节切片([]byte
)的操作函数。这个包通常用于在内存中处理二进制数据,例如对字节切片的拼接、分割和修改。如果你需要在内存中操作数据而不需要涉及文件或网络读写,bytes
包非常有用。 -
bufio包:
bufio
包是为了性能而设计的。它提供了带缓冲的读写功能,可以减少频繁的系统调用,从而提高读写效率。如果你需要高性能的文件读写,特别是在处理大文件时,bufio
包通常是首选。它包括Reader
和Writer
类型,可用于创建带缓冲的读写对象。
综上所述,你应该根据具体的需求和性能要求选择适当的包。一般情况下,io
包用于通用的读写操作,os
包用于文件系统操作,bytes
包用于内存中的二进制数据操作,而bufio
包则用于提高读写性能。