Go语言基础
介绍
目录操作
创建
删除
重命名
遍历目录
修改权限
文件操作
创建
打开关闭
删除
重命名
修改权限
读文件
写文件
文件定位
拷贝
测试
单元测试
基准测试
示例
介绍
- 本文介绍Go语言中目录操作(创建目录、删除目录、重命名、遍历目录、修改权限)、文件操作(创建、打开关闭、删除、重命名、修改权限、读文件、写文件、文件定位、拷贝)、测试(单元测试、基准测试、示例)等相关知识。
目录操作
- 在计算机中,目录是组织和存储文件的一种方式,可以多层嵌套结构。
- Go语言提供标准包 os 中相关方法对目录进行操作。
创建
package main
import (
"fmt"
"os"
)
func main() {
var path string = "./test_dir"
// 创建单层目录,若 path 存在一个以上不存在目录,则创建失败
// 目录已经存在,创建失败
err := os.Mkdir(path, 0755)
if err != nil {
fmt.Println("create dir failed")
} else {
fmt.Println("create dir succeed")
}
path = "./test_dir/a/b"
// 创建多层目录,未知目录嵌套数量大于等于零个
err = os.MkdirAll(path, 0755)
if err != nil {
fmt.Println("create dir failed")
} else {
fmt.Println("create dir succeed")
}
}
删除
package main
import (
"fmt"
"os"
)
func main() {
var path string = "./test_dir"
// 删除单层目录,若删除目录存在子目录,则删除失败
// 删除的目录不存在时,删除失败
err = os.Remove(path)
if err != nil {
fmt.Println("remove dir failed")
} else {
fmt.Println("remove dir succeed")
}
// 删除多层目录,不必关注目录是否存在
path = "./test_dir"
err = os.RemoveAll(path)
if err != nil {
fmt.Println("remove dir failed")
} else {
fmt.Println("remove dir succeed")
}
}
重命名
package main
import (
"fmt"
"os"
)
func main() {
var path string = "./test_dir"
err := os.Mkdir(path, 0755)
if err != nil {
fmt.Println("create dir failed")
} else {
fmt.Println("create dir succeed")
}
// 重新命名时,新名称已经存在时,命名失败
err = os.Rename(path, "./test_dir_new")
if err != nil {
fmt.Println("rename dir failed")
} else {
fmt.Println("rename dir succeed")
}
}
遍历目录
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
var path string = "./../../src"
// 读取 path 目录下所有目录,注意只读取单层,若 path 目录不存在读取失败
dir, err := os.ReadDir(path)
if err != nil {
fmt.Println("read dir failed")
} else {
fmt.Println("read dir succeed")
for _, v := range dir {
fmt.Println("Name: ", v)
}
}
// 遍历子目录下所有文件和子目录
sDir := new([]os.FileInfo)
err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
*sDir = append(*sDir, info)
return nil
})
if err != nil {
fmt.Println("read dir failed")
} else {
fmt.Println("read dir succeed")
for _, v := range *sDir {
fmt.Println("Name: ", v.Name())
}
}
}
修改权限
package main
import (
"fmt"
"os"
)
func main() {
var path string = "./test_dir"
err := os.Mkdir(path, 0755)
if err != nil {
fmt.Println("create dir failed")
} else {
fmt.Println("create dir succeed")
}
// 0777 为八进制权限表示方式
// 权限分三组:所有者(user)、组(group)和其他人(others)
// 每组权限又分为读(r)、写(w)和执行(x)
// 例如:rwxrw-r--(对应数组421|420|400,八进制表示0764)
err = os.Chmod(path, 0777)
if err != nil {
fmt.Println("chmod failed")
} else {
fmt.Println("chmod succeed")
}
}
文件操作
- 在计算机中,文件是非常重要的IO,可以存储文件或进行数据交换等,Linux系统更是"一切皆文件"。
- 在Go语言中,主要操作文件的包在 os 中。
创建
package main
import (
"fmt"
"os"
)
func main() {
var name string = "./test_dir/test_file.txt"
// 创建文件,路径错误会创建失败,若不存在则创建,若存在则清空文件内容
file, err := os.Create(name)
if err != nil {
fmt.Println("create file failed")
} else {
fmt.Println("create file succeed")
defer file.Close()
}
}
打开关闭
package main
import (
"fmt"
"os"
)
func main() {
var name string = "./test_dir/test_file.txt"
// 打开文件,路径错误会打开失败,文件不存在会打开失败,返回文件指针与错误信息
file, err := os.Open(name)
if err != nil {
fmt.Println("open file failed")
} else {
fmt.Println("open file succeed")
// 使用 defer 延迟关闭方法调用
defer file.Close()
}
// 通用的文件打开调用,通过标识可创建、只读、只写、追加、截断等打开文件
// 第三个参数为权限,创建时使用,返回文件指针与错误信息
name = "./test_dir/test_file2.txt"
f, e := os.OpenFile(name, os.O_RDONLY|os.O_CREATE|os.O_APPEND, 0755)
if e != nil {
fmt.Println("open file failed")
} else {
fmt.Println("open file succeed")
// 使用 defer 延迟关闭方法调用
defer f.Close()
}
}
删除
package main
import (
"fmt"
"os"
)
func main() {
name := "./test_dir/test_file2.txt"
// 删除文件,文件不存在或路径错误删除失败
err = os.Remove(name)
if err != nil {
fmt.Println("remove file failed")
} else {
fmt.Println("remove file succeed")
}
// 删除文件,不必判断文件是否存在或路径是否正确
err = os.RemoveAll(name)
if err != nil {
fmt.Println("remove file failed")
} else {
fmt.Println("remove file succeed")
}
}
重命名
package main
import (
"fmt"
"os"
)
func main() {
var name string = "./test_dir/test_file.txt"
// 文件重命名,路径错误或对应目录下新文件名已经存在,重命名失败
err := os.Rename(name, "./test_dir/test_file2.txt")
if err != nil {
fmt.Println("rename file failed")
} else {
fmt.Println("rename file succeed")
}
}
修改权限
package main
import (
"fmt"
"os"
)
func main() {
var name string = "./test_dir/test_file2.txt"
// 文件访问权限修改
err := os.Chmod(name, 0744)
if err != nil {
fmt.Println("chmod failed")
} else {
fmt.Println("chmod succeed")
}
}
读文件
package main
import (
"fmt"
"io"
"os"
)
func main() {
//读取文件
file, err := os.OpenFile("./test_dir/test_file2.txt", os.O_RDONLY, 0755)
if err != nil {
fmt.Println("open file failed", err)
return
}
defer file.Close() //main 函数结束前执行文件资源释放
fmt.Println("open file succeed")
// 方式一:打开文件读取
//定义参数切片
var arr [1024]byte = [1024]byte{0}
result := arr[:]
n, err := file.Read(result) //以切片的形式读取
//读取过程中出现异常
if err != nil && err != io.EOF {
fmt.Println("read file failed", err)
return
}
fmt.Printf("byte size: %d\n", n)
fmt.Printf("file content: %s\n", string(result[0:n]))
for {
n, err = file.Read(result) //以切片的形式读取
//读取过程中出现异常
if err == io.EOF || n == 0 {
break
}
if err != nil {
fmt.Println("read file failed", err)
return
}
fmt.Printf("byte size: %d\n", n)
fmt.Printf("file content: %s\n", string(result[0:n]))
}
// 文件判断读取是否完成
fmt.Println("read file over", err)
// 方式二:使用 bufio 读取
// 创建 bufio 缓冲区读取
reader := bufio.NewReader(file)
/*
for { //循环读取内存,输出到程序中
str, err := reader.ReadString('\n') //按行读取
if err == io.EOF {
fmt.Print(str)
return
}
if err != nil {
fmt.Println("文件读取异常", err)
return
}
fmt.Print(str)
}
*/
}
写文件
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// 打开文件,以追加方式写入
file, err := os.OpenFile("./test_dir/test_file2.txt", os.O_WRONLY|os.O_APPEND, 0755)
if err != nil {
fmt.Println("open file failed", err)
return
}
defer file.Close() //main 函数结束前执行文件资源释放
fmt.Println("open file succeed")
// 方式一:直接追加数据
// 字节切片写入
file.Write([]byte("write file data, slice\n"))
// 字符串写入
str := "string write"
file.WriteString(str)
// 方式一:使用 bufio 追加数据
// 文件写入缓冲区
w := bufio.NewWriter(file)
//内容写入缓冲区
w.WriteString("\nbufio write data\n")
//缓冲区数据刷新
w.Flush()
}
文件定位
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开文件,默认文件指针偏移量为0,即在文件起始位置
file, err := os.OpenFile("./test_dir/test_file2.txt", os.O_RDONLY, 0755)
if err != nil {
fmt.Println("open file failed", err)
return
}
defer file.Close() //main 函数结束前执行文件资源释放
fmt.Println("open file succeed")
// 此时读取文件字节数,文件实际数据不超过1000字节
//定义参数切片
var arr [1024]byte = [1024]byte{0}
result := arr[:]
n, err := file.Read(result) //以切片的形式读取
//读取过程中出现异常
if err != nil && err != io.EOF {
fmt.Println("read file failed", err)
return
}
fmt.Printf("byte size: %d\n", n)
// 以上操作读完文件后,文件指针已经指向文件末尾,此时不可能继续读取文件内容
// 将文件指针移动到文件起始位置
// os.SEEK_CUR, os.SEEK_CUR is deprecated
off, e := file.Seek(0, io.SeekStart) // 相对于起始位置偏移值
if e != nil {
fmt.Println("seek filed")
return
}
fmt.Println("off: ", off)
n, err = file.Read(result) //以切片的形式读取
//读取过程中出现异常
if err != nil && err != io.EOF {
fmt.Println("read file failed", err)
return
}
fmt.Printf("byte size: %d\n", n)
}
拷贝
// 调用 Copy 方法实现文件复制
package main
import (
"io"
"os"
)
// 文件复制函数
func CopyFile(src, dst string) (err error) {
in, err := os.OpenFile(src, os.O_RDONLY, 0744)
if err != nil {
return
}
defer in.Close()
// 文件不存在就创建
out, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0754)
if err != nil {
return
}
defer out.Close()
_, err = io.Copy(out, in)
return
}
func main() {
src := "./test_dir/test_file2.txt"
dst := "./test_dir/test_file.txt"
err := CopyFile(src, dst)
if err != nil {
panic(err)
}
}
单元测试
- 软件开发重要环节之一就是对所写代码进行测试,编写测试用例能确保一些问题能在此阶段发现并修改。
- Go语言中的测试依赖 go test 命令在包目录内,格式以 *_test.go 为后缀名的源代码文件都是 go test 测试的一部分。
- 在 *_test.go 文件中有三种类型的函数,单元测试函数、基准测试函数 和示例函数。
类型 | 格式 | 备注 |
---|---|---|
单元测试 | 前缀为Test | 测试逻辑 |
基准测试 | 前缀为Benchmark | 测试性能 |
示 例 | 前缀为Example | 提供示例 |
- 用来测试的代码必须以 _test.go 结尾。
- 单元测试的函数名必须以 Test 开头,只有一个参数,类型是 *testing.T。
- 单元测试函数名 Test 后,被测函数名首字母必须大写。
- 更多功能请参照官方文档:包testing。
单元测试
// pkgtest.go 源文件
package pkgtest
func Add[T int | float32](a, b T) T {
return a + b
}
func sub[T int | float32](a, b T) T {
return a - b
}
// pkgtest_test.go 源文件
package pkgtest
import "testing"
// Test开头,函数名首字母大写
package pkgtest
import "testing"
func TestAdd(t *testing.T) {
var a, b int = 10, 20
if 31 != Add(a, b) {
t.Error("Test failed")
return
}
t.Log("Test succeed")
}
func TestSub(t *testing.T) {
var a, b int = 10, 20
if 31 != sub(a, b) {
t.Error("Test failed")
return
}
t.Log("Test succeed")
}
// 在终端运行指令 go test -v 输出测试结果
// 在终端运行指令 go test -cover -run -coverprofile='.\c.out' -coverpkg=pkgtest 输出覆盖测试结果
// 在终端运行指令 go tool cover -html='.\c.out' -o coverage.html 将结果转换为网页形式打开
基准测试
-
基准测试或压力测试必须以 Benchmark 开头,并且只有参数 *testing.B。
func BenchmarkAdd(b *testing.B) {
var a, c int = 10, 20
for i := 0; i < 100; i++ {
Add(a, c)
}
}// 在终端运行指令 go test -run "none" -bench . -benchmem 执行基准测试
示例
func ExampleAdd() {
var a, c int = 10, 20
fmt.Println("a + c = ", a+c)
}