• Go 言 Go 语,一文看懂 Go 语言文件操作


    ⛳️ 实战场景

    本篇博客为大家再次带来 Go 语言的基础知识,这次要学习的内容是 Go 中的文件操作。

    打开关闭文件

    在 Go 中操作文件,首先要做的就是导入 os 模块,该模块中具备相关函数定义。

    package main
    
    import (
    	"fmt"
    	"os"
    )
    
    func main() {
    	// 打开文件
    	file, err := os.Open("./ca.txt")
    	if err != nil {
    		fmt.Println("文件打开失败", err)
    		return
    	}
    	print(file) // 输出地址 0xc000006028
    	// 关闭文件
    	file.Close()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    如果文件打开失败,直接展示错误信息,正确的话,会返回 file 对象的地址。

    读取文件

    使用 Read 函数读取文件,其定义如下所示:

    func (f *File) Read(b [] byte)(n int,err error)
    
    • 1

    从定义中可以发现,Read 函数会返回 2 个值,第一个是读取的字节数,第二个是当读取报错时,返回错误信息,示例代码如下所示:

    package main
    
    import (
    	"fmt"
    	"io"
    	"os"
    )
    
    func main() {
    	// 打开文件
    	file, err := os.Open("./ca.txt")
    	if err != nil {
    		fmt.Println("打开文件失败,错误信息:", err)
    		return
    	}
    
    	// 为了防止忘记关闭文件,可使用defer注册文件关闭语句
    	defer file.Close()
    
    	// Read方法读取数据
    	var tmp = make([]byte, 128)
    
    	// 读取文件
    	n, err := file.Read(tmp)
    
    	// 碰到 io.EOF 表示文件读取到末尾
    	if err == io.EOF {
    		fmt.Println("文件读取完毕")
    		return
    	}
    	if err != nil {
    		fmt.Println("读取文件失败,错误信息:", err)
    		return
    	}
    
    	fmt.Printf("读取了 %d 字节数据\n", n)
    
    	fmt.Println(string(tmp[:n]))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    输出如下内容:

    读取了 24 字节数据
    姓名:梦想橡皮擦
    
    • 1
    • 2

    读取到 24 个字节,标准的中文占 3 个字节。

    但是上述代码最大的问题就是,我们给变量 tmp,即数组 tmp 仅设置了 128 字节,如果待读取的文件超过了改值,例如 txt 内容如下所示:

    姓名:梦想橡皮擦1
    姓名:梦想橡皮擦2
    姓名:梦想橡皮擦3
    姓名:梦想橡皮擦4
    姓名:梦想橡皮擦5
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此时运行代码,就会发现 Read 函数读取到第 128 个字节的时候,就会停止读取,间接导致读取到的数据乱码

    读取了 128 字节数据
    姓名:梦想橡皮擦1
    姓名:梦想橡皮擦2
    姓名:梦想橡皮擦3
    姓名:梦想橡皮擦4
    姓名:梦想橡��
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    解决该问题,需要用到 for 循环读取文件数据,代码如下:

    package main
    
    import (
    	"fmt"
    	"io"
    	"os"
    )
    
    func main() {
    	// 打开文件
    	file, err := os.Open("./ca.txt")
    	if err != nil {
    		fmt.Println("打开文件失败,错误信息:", err)
    		return
    	}
    	defer file.Close()
    	// 声明一个 content 切片
    	var content []byte
    	var tmp = make([]byte, 128)
    	for {
    		n, err := file.Read(tmp)
    		if err == io.EOF {
    			fmt.Println("文件读取完毕")
    			break
    		}
    		if err != nil {
    			fmt.Println("读取文件失败,错误信息:", err)
    			return
    		}
    		// 追加数据
    		content = append(content, tmp[:n]...)
    	}
    	fmt.Println(string(content))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    上述代码声明了一个动态数组,即切片,解决了读取数据不足的问题。

    bufio 读取文件

    该函数可以一次读取一行数据,示例代码如下:

    func main() {
    	file, err := os.Open("./ca.txt")
    	if err != nil {
    		fmt.Println("打开文件失败,错误信息:", err)
    		return
    	}
    	defer file.Close()
    	reader := bufio.NewReader(file)
    	for {
    		// 逐行读取数据
    		line, err := reader.ReadString('\n')
    		if err == io.EOF {
    			if len(line) != 0 {
    				fmt.Println(line)
    			}
    			fmt.Println("文件读取完毕")
    			break
    		}
    		if err != nil {
    			fmt.Println("读取文件失败,错误信息:", err)
    			return
    		}
    		fmt.Print(line)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    该函数与 Python 中的 readline 具备同样的效果,接下来演示一下读取整个文件,代码如下:

    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    )
    
    func main() {
    	content, err := ioutil.ReadFile("./ca.txt")
    	if err != nil {
    		fmt.Println("打开文件失败,错误信息:", err)
    		return
    	}
    	fmt.Println(string(content))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注意导入模块的时候,直接导入了 io 包中的 ioutil 函数。

    写文件

    使用 os.OpenFile() 函数可以指定模式打开文件,即可以写入的方式打开文件。

    写入文件最常用的函数是 WriteWriteString,示例代码如下所示:

    package main
    
    import (
    	"fmt"
    	"os"
    )
    
    func main() {
    	file, err := os.OpenFile("ca.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
    	if err != nil {
    		fmt.Println("打开文件失败,错误信息:", err)
    		return
    	}
    	defer file.Close()
    
    	name := "橡皮擦"
    	file.Write([]byte(name))  //写入字节切片
    	file.WriteString("梦想橡皮擦") //写入字符串
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    使用该方式写入文件,会覆盖之前的文件内容,查看结果可直接打开目录下的 ca.txt 进行查看。

    我们将 os.OpenFile("ca.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666) 中的参数进行单独的说明。

    第一个参数表示文件名,第二个参数是打开文件的模式,具体模式如下所示:

    • os.O_WRONLY:只写;
    • os.O_CREATE:创建文件;
    • os.O_RDONLY:只读;
    • os.O_RDWR:读写;
    • os.O_TRUNC:清空;
    • os.O_APPEND:追加。

    可以看到与 Python 中的文件模式基本一致。

    最后一个参数值 0666 表示文件权限(八进制),这与 linux 文件权限数字一致,读 r 等于 0,写 w 表示 2,执行 x 等于 1,所以 666 表示的是文件可读,可写。

    在文件写入部分,还存在 bufio.NewWriter 整行写入,ioutil.WriteFile 整体写入等内容,可以学习的时候重点查阅一下。

    📢📢📢📢📢📢
    💗 你正在阅读 【梦想橡皮擦】 的博客
    👍 阅读完毕,可以点点小手赞一下
    🌻 发现错误,直接评论区中指正吧

    从订购之日起,案例 5 年内保证更新

  • 相关阅读:
    table表格初始化根据字段数字排序,table表格进入后返回上一级设置,第一级隐藏
    C语言sizeof()计算空间大小为8的问题
    openGemini 社区人才培养计划:助力成长,培养新一代云原生数据库人才
    目标检测算法
    磺酸修饰/单分散氢氧化钙/聚苯乙烯微球/载对苯二酚聚苯乙烯-二乙烯苯交联微球的性能
    【DELL】戴尔笔记本PE下没有硬盘解决方法
    MySQL数据库期末考试试题及参考答案(08)
    Android中依赖版本统一管理
    GEE/PIE遥感大数据处理与典型案例
    重温 JavaScript 系列(2):数组去重、类数组转换数组
  • 原文地址:https://blog.csdn.net/hihell/article/details/126086625