go语言基础 下
1、常用包
1、strings
strings包内提供了一系列对字符串操作的函数
package stringsdemo
import (
"fmt"
"strings"
)
func Test() {
str := "nihaoaaaaa heiheiwoshi SB"
fmt.Println(str[0])
//判断某个字符是由包含了指定的内容
fmt.Println(strings.Contains(str, "hao"))
//判断某个字符串是否包含了多个字符串的另一个
fmt.Println(strings.ContainsAny(str, "ca"))
//统计这个字符在指定字符串中出现的数量
fmt.Println(strings.Count(str, "aa"))
str2 := []string{"a", "b", "c", "d", "e", "f", "g"}
//字符合并,sep为连接的分隔符
str3 := strings.Join(str2, "-")
//用sep切分字符串
str4 := strings.Split(str3, "-")
fmt.Println(str4)
}
还有很多,可以点进strings包的源码进行查看。
2、strconv
strconv字符串转换包
package stringsdemo
import (
"fmt"
"strconv"
)
func Test() {
//字符串与bool类型的转化
//字符串转化为bool值(解析:bool)
//bool转为字符串(格式化:format)
a1 := "false"
b1, err := strconv.ParseBool(a1)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%T,%t\n", b1, b1)
a2 := strconv.FormatBool(b1)
fmt.Printf("%T,%s\n", a2, a2)
//整数与字符串之间的转化
a3 := "10"
b2, _ := strconv.Atoi(a3)
fmt.Printf("%T,%d\n", b2, b2)
//参数——原始字符串——进制(10进制)——整数类型、int64,int32..
b3, _ := strconv.ParseInt(a3, 10, 64)
fmt.Printf("%T,%d\n", b3, b3)
b4 := strconv.FormatInt(b3, 10)
fmt.Printf("%T,%s\n", b4, b4)
b5 := strconv.Itoa(b2)
fmt.Printf("%T,%s\n", b5, b5)
}
3、time
一些跟时间相关的函数和常量
package stringsdemo
import (
"fmt"
"time"
)
// 获取当前时间 now
func time1() {
// 返回值为Time结构体 : 常量:日月年时分秒 周日-周六 方法:获取常量,计算。
now := time.Now()
year := now.Year()
month := now.Month()
day := now.Day()
hour := now.Hour()
minute := now.Minute()
second := now.Second()
// 2023-2-23 20:40:31
fmt.Printf("%d-%d-%d %d:%d:%d\n", year, month, day, hour, minute, second)
}
func time2() {
now := time.Now()
// 时间格式化 2023-02-23 20:43:49
// 固定的:"2006-01-02 15:04:05"
fmt.Println(now.Format("2006-01-02 15:04:05")) // 24小时制
fmt.Println(now.Format("2006-01-02 03:04:05 PM")) // 12小时制
}
// 将字符串格式化为Time对象
func time3() {
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
fmt.Println(err)
return
}
// 将字符串解析为时间 Time
timeStr := "2023-02-23 20:53:08"
// layout 格式 时间字符串 时区位置 , 需要和前端传递的格式进行匹配
timeObj, _ := time.ParseInLocation("2006-01-02 15:04:05", timeStr, loc)
fmt.Println(timeObj)
}
// 时间戳:更多时候和随机数结合
func time4() {
now := time.Now()
timestamp1 := now.Unix() // 时间戳
timestamp2 := now.UnixNano() // 纳秒的时间数
fmt.Println(timestamp1)
fmt.Println(timestamp2)
// 通过 Unix 转换time对象
timeObj := time.Unix(timestamp1, 0) // 返回time对象
year := timeObj.Year()
month := timeObj.Month()
day := timeObj.Day()
hour := timeObj.Hour()
minute := timeObj.Minute()
second := timeObj.Second()
fmt.Printf("%d-%d-%d %d:%d:%d\n", year, month, day, hour, minute, second)
}
4、rand
使用math/rand包生成随机数
package main
import (
"fmt"
"math/rand"
"time"
)
// random随机数- math/rand
func main() {
// 获取一个随机数
num1 := rand.Int()
fmt.Println("num1:", num1)
// 随机需要一个随机数的种子,如果种子一样,那么结果一致
// n范围(0-n)
num2 := rand.Intn(100)
fmt.Println("num2:", num2) // 7
// 需要一个随时都在发生变化的量 时间戳
timestamp := time.Now().Unix()
// 设置随机数种子, 使用时间戳
// 种子只需要设置一次即可。
rand.Seed(timestamp) // 每次执行都不同
fmt.Println(num1)
}
}
GO语言现在貌似不在需要初始化随机数种子
2、I/O操作
文件就是存储在磁盘上的数据,文件分为二进制文件和文本文件
go中操作文件是通过os操作系统包,里面封装了底层的文件描述符和相关信息fileInfo,同时封装了Read和Write方法。
package main
import (
"fmt"
"os"
)
func main() {
//使用Stat函数返回文件信息,里面为文件的路径
fileInfo, _ := os.Stat("D:\\Goland\\library\\src\\HelloWorld\\hello_world.go")
fmt.Println(fileInfo.Name()) //文件名
fmt.Println(fileInfo.Size()) //文件大小
fmt.Println(fileInfo.ModTime()) //修改时间
fmt.Println(fileInfo.IsDir()) //是否是文件夹
fmt.Println(fileInfo.Mode()) //权限
}
Stat返回类型为FileInfo类型
1、创建目录文件
package main
import (
"fmt"
"os"
)
func main() {
//---------------------------创建目录--------------------------------
//创建文件夹,只能创建一层文件夹,os.ModePerm为权限0777
err1 := os.Mkdir("D:\\Goland\\library\\src\\HelloWorld\\hello", os.ModePerm)
if err1 != nil {
panic(err1)
}
//移除文件夹,通过此方法只能删除单个空文件夹
err2 := os.Remove("D:\\Goland\\library\\src\\HelloWorld\\hello")
if err2 != nil {
panic(err2)
}
//递归创建多层文件夹
err3 := os.MkdirAll("D:\\Goland\\library\\src\\HelloWorld\\hello\\aa\\bb", os.ModePerm)
if err3 != nil {
panic(err3)
}
//递归删除多层文件夹,删除这个目录下的所有东西,强制删除
err4 := os.RemoveAll("D:\\Goland\\library\\src\\HelloWorld\\hello\\aa\\bb")
if err4 != nil {
panic(err4)
}
//---------------------------创建文件--------------------------------
//os.Create()若存在则打开(即返回操作指针,可以对文件进行操作),不存在则创建
file, _ := os.Create("a.go") //相对路径
fmt.Println(file)
//删除文件
os.Remove("a.go")
}
2、打开文件
package main
import (
"fmt"
"os"
)
func main() {
//打开文件,返回文件指针
file1, err1 := os.Open("hei.txt")
if err1 != nil {
fmt.Println(err1)
return
}
fmt.Println(file1)
//打开文件的时候,选则打开方式,O_RDWR可读可写
//第三个参数的作用是如果文件不存在创建参数时权限的选项
file2, err2 := os.OpenFile("hei.txt", os.O_RDWR|os.O_CREATE, os.ModePerm)
if err2 != nil {
fmt.Println(err2)
}
fmt.Println(file2)
//可以同时打开,因为打开方式不同,即两个文件指针,指向同一个文件
}
3、读取文件
package main
import (
"fmt"
"os"
)
func main() {
//打开文件
file1, err1 := os.Open("hei.txt")
if err1 != nil {
fmt.Println(err1)
return
}
//操作关闭后,关闭文件
defer file1.Close()
//创建容器切片
buf := make([]byte, 1024)
//将文件内的内容读取到buf中,返回值为文件长度,
//err为错误,若出现EOF错误,则代表文件读取完毕
size, err2 := file1.Read(buf)
if err2 != nil {
fmt.Println(err2)
return
}
if size != 0 {
fmt.Println(string(buf[:size]))
}
}
4、写入文件
package main
import (
"fmt"
"os"
)
func main() {
//打开文件,建立连接
filename := "hei.txt"
//若不加os.O_APPEND,则光标会在最前面,从头写,会覆盖原内容
//通过os.O_APPEND,则向文件后面追加内容
file, _ := os.OpenFile(filename, os.O_RDWR|os.O_APPEND, os.ModePerm)
defer file.Close()
//写文件,Write方法写入内容为字节切片
bs := []byte{65, 66, 67, 68, 69}
n, err := file.Write(bs)
if err != nil {
fmt.Println(err)
}
fmt.Println(n)
//写入字符串
n, err = file.WriteString("hello world")
if err != nil {
fmt.Println(err)
}
fmt.Println(n)
}
5、seeker
seeker是一个接口类,里面实现了唯一Seek函数,用于确定光标的位置,以便确定下次读取或写入开始的位置。
Seek函数有两个参数,即offset和whence,先解释第二个参数,该参数有三个值,如下:
SeekStart:文件的起始位置,SeekCurrent:文件当前位置,SeekEnd:文件结尾位置
offset:为偏移量
要想移动文件光标位置,首先要确定的是从哪里开始,因此要有第二个参数,再通过偏移量,即可确定光标位置。
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 读取文件
file, _ := os.OpenFile("D:\\Goland\\library\\src\\HelloWorld",
os.O_RDWR, os.ModePerm)
// defer close
defer file.Close()
// 测试seek
// 相对开始位置。io.SeekStart
// 相对于文件末尾, io.SeekEnd
file.Seek(2, io.SeekStart)
buf := []byte{0}
file.Read(buf)
fmt.Println(string(buf))
// 相对于当前位置
file.Seek(3, io.SeekCurrent)
file.Read(buf)
fmt.Println(string(buf))
// 在结尾追加内容
file.Seek(0, io.SeekEnd)
file.WriteString("xixixxixi")
}
6、文件操作案例
1、断点续传
传续到一半发生错误,传输一半的文件,下次能够从中断的位置进行传输
package main
import (
"fmt"
"io"
"os"
"strconv"
"time"
)
func main() {
io.Seeker()
srcFile := "C:\\Users\\zhangyahui\\Desktop\\client\\wallhaven-9mdkv1.jpg"
dstFile := "D:\\Goland\\library\\src\\HelloWorld\\server\\wh.jpg"
tempFile := "D:\\Goland\\library\\src\\HelloWorld\\temp.txt"
file1, _ := os.Open(srcFile)
defer file1.Close()
file2, _ := os.OpenFile(dstFile, os.O_RDWR|os.O_CREATE, os.ModePerm)
defer file2.Close()
file3, _ := os.OpenFile(tempFile, os.O_RDWR|os.O_CREATE, os.ModePerm)
//1、读取temp.txt
//设定缓冲区字节切片大小
buf := make([]byte, 1024)
//读取file3.txt获取偏移量
file3.Seek(0, io.SeekStart)
//将偏移量存入buf中
n, _ := file3.Read(buf)
//此时buf中的偏移量为字节类型,先转乘string,再转成int类型
count, _ := strconv.ParseInt(string(buf[:n]), 10, 64)
//2、设置file1,file2的偏移量
file1.Seek(count, io.SeekStart)
file2.Seek(count, io.SeekStart)
//开始读写
bufData := make([]byte, 1024)
total := int(count)
for {
readNum, err := file1.Read(bufData)
if err == io.EOF {
fmt.Println("chuanshuwanbi")
time.Sleep(time.Second * 3)
file3.Close()
os.Remove(tempFile)
break
}
writeNum, _ := file2.Write(bufData[:readNum])
total += writeNum
file3.Seek(0, io.SeekStart)
file3.WriteString(strconv.Itoa(total))
}
}
2、遍历文件夹
package main
import (
"fmt"
"log"
"os"
)
func main() {
dir := "D:\\Goland\\library\\src\\HelloWorld"
tree(dir)
}
func tree(dir string) {
fileInfos, err := os.ReadDir(dir)
if err != nil {
log.Println(err)
}
for _, fileInfo := range fileInfos {
// 文件夹中文件的全路径展示
filename := dir + "\\" + fileInfo.Name()
fmt.Println(fileInfo.Name())
// 如果是文件夹,再次遍历
if fileInfo.IsDir() {
//递归遍历
tree(filename)
}
}
}