GO语言学习(九)----GO语言其他标准库

目录

一、IO包

1.1、常用函数

1.2、ioutil包

二、log

2.1、log使用

三、builtin

常用函数

3.1 append

3.2、new和make

四、bytes

4.1常用函数

4.2、Reader类型

4.3 buffer

五、errors

六、sort包

6.1 普通类型

6.2 自定义类型

6.3 复杂结构

6.3.1、二位切片 [][]int

6.3.2 []map[string]int

6.3.3 自定义结构体 

七、time 

7.1、基本使用

7.2、时间戳

时间戳转换为普通的时间格式

 ADD

SUB 

Equal

 Before

After

 定时器

7.3、时间格式化

 7.4、解析字符串格式的时间

八、json

核心的两个函数

​编辑

两个核心结构体

8.1、结构体和json的相互转化

8.2、从文件中读取json转换为map,向文件中写 从map转换为json

九、XML

核心的两个函数

两个核心结构体

十、math

10.1、常量

10.2、常用函数

10.3 随机数


一、IO包

Go语言中,为了方便开发者使用,将io操作封装在了如下几个包中

  • io为IO原语提供基本的接口 例如 os相关内容中学过的 File中Reader和Writer
  • io/ioutil封装了一些使用的IO函数
  • fmt实现格式化IO,类似C中的printf和scanf
  • bufio实现带缓冲IO

1.1、常用函数

io包所在地址

io package - io - Go Packages

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.ReadSliceReadBytesReadString
以一个符号为分割,读取第一个切片
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语言中,用于读写操作的常用包包括ioosbytesbufio,而哪个包最常用取决于你的具体需求和使用场景。每个包都有其特定的用途和优势:

  1. io包: io包提供了一组通用的接口和函数,用于处理输入和输出操作。它定义了ReaderWriter接口,允许你使用通用的方式进行数据读取和写入。这些接口和函数通常用于抽象不同的数据源和目标,因此在编写通用的、可扩展的代码时非常有用。io包是Go中读写操作的基础。

  2. os包: os包是操作系统的封装,提供了访问文件系统的功能。它包含文件的打开、创建、删除等函数。如果你需要直接操作文件、目录和文件属性,os包通常是首选。它的函数可以用于文件的打开、读取、写入和关闭,以及文件操作相关的权限和属性设置。

  3. bytes包: bytes包提供了对字节切片([]byte)的操作函数。这个包通常用于在内存中处理二进制数据,例如对字节切片的拼接、分割和修改。如果你需要在内存中操作数据而不需要涉及文件或网络读写,bytes包非常有用。

  4. bufio包: bufio包是为了性能而设计的。它提供了带缓冲的读写功能,可以减少频繁的系统调用,从而提高读写效率。如果你需要高性能的文件读写,特别是在处理大文件时,bufio包通常是首选。它包括ReaderWriter类型,可用于创建带缓冲的读写对象。

综上所述,你应该根据具体的需求和性能要求选择适当的包。一般情况下,io包用于通用的读写操作,os包用于文件系统操作,bytes包用于内存中的二进制数据操作,而bufio包则用于提高读写性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值