Golang基础-12

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)
}

起始

相关推荐
唐 城15 分钟前
curl 放弃对 Hyper Rust HTTP 后端的支持
开发语言·http·rust
星就前端叭43 分钟前
【开源】一款基于Vue3 + WebRTC + Node + SRS + FFmpeg搭建的直播间项目
前端·后端·开源·webrtc
小林coding2 小时前
阿里云 Java 后端一面,什么难度?
java·后端·mysql·spring·阿里云
AI理性派思考者2 小时前
【保姆教程】手把手教你在Linux系统搭建早期alpha项目cysic的验证者&证明者
后端·github·gpu
码银2 小时前
【python】银行客户流失预测预处理部分,独热编码·标签编码·数据离散化处理·数据筛选·数据分割
开发语言·python
从善若水2 小时前
【2024】Merry Christmas!一起用Rust绘制一颗圣诞树吧
开发语言·后端·rust
机器之心2 小时前
终于等来能塞进手机的文生图模型!十分之一体量,SnapGen实现百分百的效果
人工智能·后端
机器之心2 小时前
首次!大模型自动搜索人工生命,做出AI科学家的Sakana AI又放大招
人工智能·后端
运维&陈同学3 小时前
【模块一】kubernetes容器编排进阶实战之基于velero及minio实现etcd数据备份与恢复
数据库·后端·云原生·容器·kubernetes·etcd·minio·velero
2401_858286113 小时前
115.【C语言】数据结构之排序(希尔排序)
c语言·开发语言·数据结构·算法·排序算法