Go学习第十章——文件操作,Json和测试
Go文件操作,Json和测试
- 1 文件
- 1.1 基本介绍
- 1.2 读取的基本操作
- 1.3 写入的基本操作
- 1.4 使用案例(三个)
- 2 Go语言的Json使用
- 2.1 序列化案例
- 2.2 反序列化案例
- 3 单元测试
- 3.1 先看个需求
- 3.2 快速入门
- 3.3 入门总结
1 文件
1.1 基本介绍
文件在程序中是以流的形式来操作的。
**流:**数据在数据源(文件)和程序(内存)之间经历的路径。
**输入流(读文件):**数据从数据源(文件)到程序(内存)的路径。
**输出流(写文件):**数据从程序(内存)到数据源(文件)的路径。
在Golang里,os.File封装所以文件相关操作,File是一个结构体。
// File represents an open file descriptor.
type File struct {*file // os specific
}
1.2 读取的基本操作
方法一:使用带缓存的方式读取,适用于大文件读取
读取文件需要先了解下面的几个方法函数,需要这四步才算是一个完整的读取操作。
-
使用
os.Open()
函数打开文件- 函数原型:
func Open(name string) (*os.File, error)
- 示例代码:
file, err := os.Open("test.txt") if err != nil {log.Fatal(err) }
完整代码:
func main() {// 1.file 被叫做 file对象,file指针 ,file文件句柄file, err := os.Open("D:\\Desktop\\test.txt")if err != nil {log.Fatal(err)}// 输出文件fmt.Printf("file=%v", file)// 关闭文件err = file.Close()if err != nil {fmt.Println("close file err=", err)} }
输出结果:
file=&{0xc00009aa00}
- 函数原型:
-
使用
bufio.NewReader()
函数创建读取缓冲区- 函数原型:
func NewReader(rd io.Reader) *bufio.Reader
- 示例代码:
reader := bufio.NewReader(file) // 默认缓冲区为4096
- 函数原型:
-
使用
ReadString()
函数读取文件内容- 函数原型:
func (b *bufio.Reader) ReadString(delim byte) (string, error)
- 示例代码:
content, err := reader.ReadString('\n') if err != nil && err != io.EOF {log.Fatal(err) }
- 函数原型:
-
关闭文件
- 示例代码:
file.Close()
将上面的步骤合起来,就是读取文件的全过程:
func main() {// 1.file 被叫做 file对象,file指针 ,file文件句柄file, err := os.Open("D:\\Desktop\\test.txt")if err != nil {log.Fatal(err)}// 输出文件fmt.Printf("file=%v \n", file)// 关闭文件(defer 最后结束再执行)defer func(file *os.File) {err := file.Close()if err != nil {fmt.Println("close file err=", err)}}(file)// 创建读取缓冲区reader := bufio.NewReader(file)// 读取缓冲区内容,也就是文件内容content, err := reader.ReadString('\n')if err != nil && err != io.EOF {log.Fatal(err)}// 打印fmt.Printf("content=%v", content)
}
输出结果:
file=&{0xc000078a00}
content=你好,Hello Go File!!
方法二:一次性将文件读取到内存中,适用于文件不大的情况
- 使用
ReadFile()
函数读取文件内容,读取整个文件的操作已经封装在函数内,不用手动打开或关闭文件。。
- 函数原型:
func ReadFile(name string) ([]byte, error)
- 示例代码:
data, err := io.ReadFile("test.txt")
if err != nil {log.Fatal(err)
}
代码示例:
func main() {// 一次性读取文件data, err := os.ReadFile("D:\\Desktop\\test.txt")if err != nil {log.Fatal(err)}fmt.Println(string(data))
}
输出结果:
你好,Hello Go File!!
- 使用
io.ReadAll()
时,需要先手动打开文件,并在读取完成后手动关闭。(不推荐,已经被舍弃)
- 函数原型:
func ReadFile(name string) ([]byte, error)
- 示例代码:
func main() {file, err := os.Open("D:\\Desktop\\test.txt")if err != nil {log.Fatal(err)}defer file.Close()data, err := ioutil.ReadAll(file)if err != nil {log.Fatal(err)}fmt.Println(string(data))
}
输出结果:
你好,Hello Go File!
1.3 写入的基本操作
-
使用
os.Create()
函数创建文件- 函数原型:
func Create(name string) (*os.File, error)
- 示例代码:
file, err := os.Create("output.txt") if err != nil {log.Fatal(err) }
- 函数原型:
-
使用
file.Write()
函数将字符串写入文件
- 函数原型:
func (f *File) Write(b []byte) (n int, err error)
- 示例代码:
_, err := file.Write([]byte("Hello, world!\n"))
if err != nil {log.Fatal(err)
}
- 关闭文件
- 示例代码:
file.Close()
将上面的步骤合起来,就是创建并写入文件的全过程:
func main() {// 创建文件file, err := os.Create("D:\\Desktop\\output.txt")if err != nil {log.Fatal("创建文件错误",err)}// 将字符串写入文件_, err = file.Write([]byte("Hello, world!\n"))if err != nil {log.Fatal("文件写入错误:", err)}err = file.Close()if err != nil {fmt.Println("关闭文件错误:", err)}
}
输出结果:无。打开文件,就能发现写入成功啦~~~~
1.4 使用案例(三个)
**案例一:**将一个文件的内容,写到另一个文件,注意,两个文件都已经存在。
方案一:通过缓存的方式
func main() {// 打开原文件inputFile, err := os.Open("D:\\Desktop\\input.txt")if err != nil {log.Fatal(err)}defer inputFile.Close()// 创建目标文件outputFile, err := os.Create("D:\\Desktop\\output.txt")if err != nil {log.Fatal(err)}defer outputFile.Close()// 创建缓冲区buffer := make([]byte, 1024)// 读取原文件并写入目标文件for {// 从原文件读取数据到缓冲区n, err := inputFile.Read(buffer)if err != nil && err != io.EOF {log.Fatal(err)}if n == 0 {break}// 将数据从缓冲区写入目标文件_, err = outputFile.Write(buffer[:n])if err != nil {log.Fatal(err)}}log.Println("文件内容写入成功!")
}
方法二:使用io.Copy()复制io流
func main() {// 打开原文件inputFile, err := os.Open("D:\\Desktop\\input.txt")if err != nil {log.Fatal(err)}defer inputFile.Close()// 创建目标文件outputFile, err := os.Create("D:\\Desktop\\output.txt")if err != nil {log.Fatal(err)}defer outputFile.Close()// 将原文件内容写入目标文件_, err = io.Copy(outputFile, inputFile)if err != nil {log.Fatal(err)}log.Println("文件内容写入成功!")
}
输出结果:2023/10/26 16:29:29 文件内容写入成功!
**案例二:**将一个图片拷贝到另一个文件夹下
func main() {srcPath := "D:\\Desktop\\img.jpg"destPath := "D:\\Desktop\\img\\image.jpg"err := copyFile(srcPath, destPath)if err != nil {fmt.Println("Failed to copy file:", err)return}fmt.Println("File copied successfully!")
}func copyFile(srcPath, destPath string) error {srcFile, err := os.Open(srcPath)if err != nil {return err}defer srcFile.Close()destFile, err := os.Create(destPath)if err != nil {return err}defer destFile.Close()_, err = io.Copy(destFile, srcFile)if err != nil {return err}return nil
}
输出结果:File copied successfully!
上述代码中,srcPath和destPath分别表示源图片文件的路径和目标文件夹的路径。
在copyFile函数中,首先使用os.Open打开源图片文件,并使用os.Create创建目标文件。然后使用io.Copy将源图片文件的内容拷贝到目标文件中。最后返回nil表示拷贝成功,或者返回拷贝过程中遇到的错误。
**案例三:**统计一个文件内容里的英文、数字、空格和其他字符数量
func main() {filePath := "D:\\Desktop\\input.txt" // 文件路径data, err := os.ReadFile(filePath)if err != nil {fmt.Printf("读取文件失败:%s\n", err)return}charsCount := make(map[string]int)for _, ch := range string(data) {switch {case unicode.IsLetter(ch):charsCount["英文"]++case unicode.IsDigit(ch):charsCount["数字"]++case unicode.IsSpace(ch):charsCount["空格"]++default:charsCount["其他字符"]++}}fmt.Printf("英文字符数量:%d\n", charsCount["英文"])fmt.Printf("数字字符数量:%d\n", charsCount["数字"])fmt.Printf("空格数量:%d\n", charsCount["空格"])fmt.Printf("其他字符数量:%d\n", charsCount["其他字符"])
}
输出结果:
英文字符数量:652
数字字符数量:67
空格数量:133
其他字符数量:107
2 Go语言的Json使用
JSON易于机器解析和生成,并有效地提升网络传输效率通常程序在网络传输时会先将数据(结构体、map等)序列化成son字符串到接收方得到ison字符串时,在反序列化恢复成原来的数据类型(结构体、map等)。这种方式已然成为各个语言的标准。
2.1 序列化案例
type Person struct {Name string `json:"name"`Age int `json:"age"`
}func main() {people := []map[string]interface{}{{"name": "Alice","age": 25,},{"name": "Bob","age": 30,},}data, err := json.Marshal(people)if err != nil {fmt.Printf("序列化失败: %s", err)return}err = ioutil.WriteFile("people.json", data, 0644)if err != nil {fmt.Printf("写入文件失败: %s", err)return}fmt.Println("JSON数据已写入文件")
}
在代码中,我们定义了一个Person
结构体,表示每个人的姓名和年龄,这里主要添加tag
,不然序列化后的是大写,不符合公共规范。然后,我们创建了一个包含多个map
的切片people
,每个map
对应一个人的信息。
使用json.Marshal()
函数将切片people
序列化为JSON数据。json.Marshal()
函数会返回一个[]byte
类型的字节切片,表示JSON数据。
然后,我们使用ioutil.WriteFile()
函数将JSON数据写入一个名为people.json
的文件。
最后,我们输出一个提醒信息,表示JSON数据已成功写入文件。
运行以上代码,会在当前目录下生成一个名为people.json
的文件,其中包含以下JSON数据:
[{"name":"Alice","age":25},{"name":"Bob","age":30}
]
这个JSON数组包含了两个map
,每个map
对应一个人的姓名和年龄。
2.2 反序列化案例
将上面的代码反过来,json格式转换成对应的数据
type Person struct {Name string `json:"name"`Age int `json:"age"`
}func main() {filePath := "D:\\Desktop\\people.json" // JSON文件路径// 读取JSON文件内容data, err := os.ReadFile(filePath)if err != nil {fmt.Printf("读取文件失败:%s\n", err)return}var people []Person// 反序列化JSON数据err = json.Unmarshal(data, &people)if err != nil {fmt.Printf("反序列化失败: %s\n", err)return}fmt.Printf("解析到%d个人的信息:\n", len(people))for _, p := range people {fmt.Printf("姓名:%s\t年龄:%d\n", p.Name, p.Age)}// 将JSON数据反序列化为map类型var peopleMap []map[string]interface{}err = json.Unmarshal(data, &peopleMap)if err != nil {fmt.Printf("反序列化为map失败: %s\n", err)return}fmt.Printf("解析到%d个人的信息:\n", len(peopleMap))for _, p := range peopleMap {fmt.Printf("姓名:%s\t年龄:%v\n", p["name"], p["age"])}
}
输出结果:
解析到2个人的信息:
姓名:Alice 年龄:25
姓名:Bob 年龄:30
解析到2个人的信息:
姓名:Alice 年龄:25
姓名:Bob 年龄:30
3 单元测试
3.1 先看个需求
在我们工作中,我们会遇到这样的情况,就是去确认一个函数,或者一个模块的结果是否正确,如下:
func addUpper(n int) int {res := 0for i := 1; i <= n; i++ {res += i}return res
}
在 main 函数中,调用 addUpper 函数,看看实际输出的结果是否和预期的结果一致,如果一致,则说明函数正确,否则函数有错误,然后修改错误.
传统方式的缺点
- 不方便,我们需要在 main 函数中去调用,这样就需要去修改 main 函数,如果现在项目正在运行,就可能去停止项目。
- 不利于管理,因为当我们测试多个函数或者多个模块时,都需要写在 main 函数,不利于我们管理和清晰我们思路
- 引出单元测试。-> testing 测试框架 可以很好解决问题。
3.2 快速入门
Go 语言中自带有一个轻量级的测试框架 testing 和自带的 go test 命今来实现单元测试和性能测试,testing 框架和其他语言中的测试框架类似,可以基于这个框架写针对相应函数的测试用例,也可以基
于该框架写相应的压力测试用例。通过单元测试,可以解决如下问题:
- 确保每个函数是可运行,并且运行结果是正确的
- 确保写出来的代码性能是好的,
- 单元测试能及时的发现程序设计或实现的逻辑错误,使问题及早暴露,便于问题的定位解决,
1. 创建一个cal.go文件,把需要测试的代码放在里面
package test01func AddUpper(n int) int {res := 0for i := 1; i <= n; i++ {res += i}return res
}
2. 创建cal_test.go文件,在里面写测试案例
import ("testing"
)func TestAddUpper(t *testing.T) {res := AddUpper(10)if res != 55 {// fmt.Printf("AddUpper(10) 执行错误,期望值=%v 实际值=%v\n", 55, res)t.Fatalf("AddUpper(10) 执行错误,期望值=%v 实际值=%v\n", 55, res)}// 如果正确,输出日志t.Logf("AddUpper(10) 执行正确。。。")
}
执行后的结果如图所示,我使用的GoLand,就比较方便:
3.3 入门总结
-
测试用例文件名必须以 test.go 结尾。 比如 cal test.go ,cal 不是固定的。
-
测试用例函数必须以 Test 开头,一般来说就是 Test+被测试的函数名,比如 TestAddUpper
-
TestAddUpper(t *tesing.T) 的形参类型必须是 *testing.T
-
一个测试用例文件中,可以有多个测试用例函数,比如 TestAddUpper、TestSub
-
运行测试用例指令
(1) cmd>go test [ 如果运行正确,无日志,错误时,会输出日志 ]
(2) cmd>go test-v [ 运行正确或是错误,都输出日志 ]
-
当出现错误时,可以使用 t.Fatalf 来格式化输出错误信息,并退出程序
-
t.Logf 方法可以输出相应的日志
-
测试用例函数,并没有放在 main 函数中,也执行了,这就是测试用例的方便之处
-
PASS 表示测试用例运行成功,FAIL 表示测试用例运行失败
-
测试单个文件,一定要带上被测试的原文件
go test -v cal test.go cal.go -
测试单个方法
go test -v -test.runTestAddUpper
相关文章:

Go学习第十章——文件操作,Json和测试
Go文件操作,Json和测试 1 文件1.1 基本介绍1.2 读取的基本操作1.3 写入的基本操作1.4 使用案例(三个) 2 Go语言的Json使用2.1 序列化案例2.2 反序列化案例 3 单元测试3.1 先看个需求3.2 快速入门3.3 入门总结 1 文件 1.1 基本介绍 文件在程序中是以流的形式来操作…...

学习不同概率分布(二项分布、泊松分布等)概念及基础语法
概率分布是描述随机变量取值的概率情况的函数。常见的概率分布包括二项分布、泊松分布等。 二项分布(Binomial Distribution):描述了一次试验中成功事件发生的次数的概率分布。它的基础语法如下: 概率质量函数:pmf(k, …...

在3台不联网的 CentOS 7.8 服务器上部署 Elasticsearch 6.8 集群
为了在3台不联网的 CentOS 7.8 服务器上部署 Elasticsearch 6.8.23 集群,并考虑到path.data和path.logs的配置,我们可以按照以下步骤进行操作: 1. 准备工作 1.1 从有网络的机器下载 Elasticsearch 6.8.23 的 RPM 包: https://w…...

CentOS 7
导入已有虚拟机 设置SSH免密登录 参考Ubuntu- 远程连接虚拟机(桥连接) 宿主机:Win10虚拟机:VMware保证宿主机和主机在同一个网段下(宿主机和主机通过手机热点连接,在特定网段内,不能更改&#…...

个人记账理财软件 Money Pro mac中文版软件介绍
Money Pro for mac是一款综合性高的理财工具,Money Pro是一套能够协同工作的工具,可用来追踪账户、管理账单以及制作预算,您可以为每个时间段设置不同的预算限值。财务一切尽在掌控之中。 Money Pro for mac软件介绍 Money Pro for mac提供一…...

DSP 开发教程(0): 汇总
目录 DSP 开发教程(0): 汇总开发环境搭建DSP 开发例程 DSP 开发教程(0): 汇总 开发环境搭建 开发环境的搭建参考: Tronlong创龙 的博客. 安装 CCS v5.5 安装 BIOS_MCSDK DSP 开发例程 名称说明led_flash此例程实现在 EVM6678L 开发板控制 LED 闪烁. 使用了 SYS/BIOS 和 MC…...

YouTrack 中如何设置邮件通知
在 YouTrack 中,默认是不会邮件通知的。 你可以为你的账号设置邮件通知。 设置的方法为单击用户属性,然后在弹出的小窗口中选择属性选项。 设置邮件通知 在通知 Tab 页面中,选择发送邮件的方式,默认这个选项是不选择的。 用户…...

Prevalence and prevention of large language model use in crowd work
本文是LLM系列文章,针对《Prevalence and prevention of large language model use in crowd work》的翻译。 众包工作中使用大型语言模型的流行率和预防 摘要1 研究1:LLM使用的普遍率2 研究2:LLM使用的预防3 讨论4 材料与方法 摘要 我们表…...

微信小程序学习(02)
页面导航 - 声明式导航 1. 导航到 tabBar 页面 tabBar 页面指的是被配置为 tabBar 的页面。 在使用<navigator> 组件跳转到指定的 tabBar 页面时,需要指定 url 属性和 open-type 属性,其中: ⚫ url 表示要跳转的页面的地址࿰…...

Transit path
一、什么是Transit path "Transit" 路径通常指的是网络上的一种数据传输路线或路径,该路线用于在计算机网络中传递数据包。这个术语通常在网络和通信领域中使用,用于描述数据从一个地方传输到另一个地方的路线或路径。 在计算机网络中&#…...

backend-learning: personal blog(1)
问题记录: 跨度太大,无法完成,遂决定从基础学起。 规划路线: 1.完成JAVA与c语言差异部分,(注解,其实没多少) 2.上springboot官网查看开发手册,了解大致原理。 3. 开始挑…...

centos7系统下,实现1台服务器免密登录多台服务器功能
SSH案例:实现kafka01服务器能够免密登录kafka02和kafka03服务器的需求(不然后面一键启动的脚本将无法使用)⭐ 1:检查每台服务器是否都安装了SSH: [rootkafka01 ~]# rpm -qa |grep ssh openssh-clients-7.4p1-21.el7.…...

【力扣SQL】几个常见SQL题
【力扣SQL】184. 部门工资最高的员工 Employee:id(主键)、name、salary、departmentId(外键) Department:id(主键)、name 出每个部门中薪资最高的员工:Department.name、…...

[Python] ModuleNotFoundError: No module named ‘_ctypes‘
Python 找不到模块 此前遇到了 python 中的 _ctypes 模块丢失的问题,经排查发现是 Pyenv 安装的 python 确实缺少了此模块,后来使用 conda 安装 Python 发现 _ctypes.cpython-37m-x86_64-linux-gnu.so 此包存在。 排查方法是先全局查找相关模块ÿ…...

牛客网刷题-(5)
🌈write in front🌈 🧸大家好,我是Aileen🧸.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流. 🆔本文由Aileen_0v0🧸 原创 CSDN首发🐒 如…...

springcloud gateway转发后getServerName被更改的问题
该问题起源于一次将代码移植到微服务产生。当使用springcloud gateway更换掉nginx网关后,出现无法登录的情况,跟进发现转发的信息里丢失了Host MimeHeaders accept */* knife4j-gateway-code ROOT content-type application/x-www-form-urlencoded …...

Linux - firewall-cmd 命令添加端口规则不生效排查
文章目录 linux 防火墙 firewall-cmd 命令详解问题排查 linux 防火墙 firewall-cmd 命令详解 基本语法 firewall-cmd --zonezone-name --add-serviceservice-name --permanent命令参数 --zone:指定要添加服务的区域名称。 --add-service:指定要添加的…...

iPhone手机屏幕分辨率
ios app测试时,需要测试应用在不同型号的苹果手机上的表现形式,可以自己在浏览器上配置。 代数设备逻辑像素尺寸缩放发布时间第一代iPhone 2G320 x 480480 x 3203.5寸1x2007年6月29日第二代iPhone 3320 x 480480 x 3203.5寸1x2008年7月11日第三代iPhone …...

文件包含漏洞(3),日志利用, 图片木马利用
日志利用, 图片木马利用 一, 利用服务器日志 通过普通的网络请求向日志文件注入代码, 再利用文件包含漏洞执行日志中的代码段. apache log: /opt/lampp/logs/access_log nginx log: /usr/local/nginx/logs/access.log 首先可以利用文件包含漏洞测试日志文件的内容是否可以显…...

java面试--线程总结
Java中有几种方式来创建线程执行任务,分别是什么? 1、继承Thread类 public class MyThread extends Thread{public static void main(String[] args) {MyThread myThread new MyThread();myThread.start();}Overridepublic void run() {System.out.pr…...

Angular-02:环境等说明
项目名不要带数字npm版本过低安装工具时加上版本号现项目完整的工具链:angular ngZorro rxjs ngrx sassvscode好用插件分享: 名称说明Auto Close Tag自动闭合html标签Auto Import自动引包(可自动生成文件路径提示方便文件导入࿰…...

pgsql 分组查询,每组取10条
需求: 按照表的字段分组,然后每组取10条结果,返回即可 sql 如下: SELECT* FROM (SELECT chk_id,feature_id,task_id, ROW_NUMBER () OVER (PARTITION BY chk_id ORDER BY chk_id) AS row_num FROM ics_check_report WHERE task…...

python,pandas ,openpyxl提取excel特定数据,合并单元格合并列,设置表格格式,设置字体颜色,
python,pandas ,openpyxl提取excel特定数据,合并单元格合并列,设置表格格式,设置字体颜色, 代码 import osimport numpy import pandas as pd import openpyxl from openpyxl.styles import Font from op…...

chatgpt论文润色 降重
用chatgpt最好要给他范例。chatgpt降重原理: https://www.bilibili.com/video/BV1Eh411M7Ug/?spm_id_from333.337.search-card.all.click&vd_sourceebc47f36e62b223817b8e0edff181613 一. 中文论文翻译成英文 1.1 直接翻译 你是一位广义零样本学习的专家&a…...

第四章 文件管理 七、文件共享
目录 一、基于索引结点的共享方式(硬链接) 1、知识回顾: 2、例子: 二、基于符号链的共享方式(软链接) 1、例子 三、总结 一、基于索引结点的共享方式(硬链接) 1、知识回顾: 索引结点,是一…...

带过期时间的localstorage封装
localstorage原本是不带过期时间的,xijs提供了一个带过期时间封装的store工具,但是用起来因为文档基本等于没有,所以干脆直接封装一个用,其中ttl是过期时间,以毫秒计算。 // 设置function setLocalStorageWithExpiry(…...

mac系统u盘启动盘制作教程,更新至macOS Sonoma 14
mac系统怎么制作装系统的u盘,如果您要在多台电脑上安装 macOS,而又不想每次都下载安装器,这时可引导安装器就会很有用。一起来看苹果电脑u盘启动盘制作教程吧。 Macos系统安装包合集包揽macos 10.15,macos 11和苹果最新系统等多个版本 1、A…...

基于单片机的智能电子鼻的设计
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、智能电子鼻系统的设计方案1.1智能电子鼻系统的设计思路1.2智能电子鼻系统的设计流程图1.3智能电子鼻系统的硬件数…...

代码随想录图论 第三天 | 130. 被围绕的区域 417. 太平洋大西洋水流问题
代码随想录图论 第三天 | 130. 被围绕的区域 417. 太平洋大西洋水流问题 一、130. 被围绕的区域 题目链接:https://leetcode.cn/problems/surrounded-regions/ 思路:题目要求沾边的不动,只改没沾边的,那么可以先dfs遍历4条边&am…...

二、【常用的几种抠图方式一】
文章目录 选框抠图快速选择工具抠图魔棒工具抠图对象选择工具抠图套索工具抠图多边形套索工具抠图磁性套索工具抠图 选框抠图 选框工具抠图适合规则的图形,如下图先使用选框工具框出对象的图轮廓,然后再选择并遮住在里边擦出图形的边缘,根据…...