李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
GO
正文
28.Golang读取文件
Leefs
2022-07-24 PM
1610℃
0条
[TOC] ### 前言 ![28.Golang读取文件01.png](https://lilinchao.com/usr/uploads/2022/07/2974068165.png) ### 一、概念 文件是数据源(保存数据的地方)的一种,文件最主要的作用就是保存数据。 文件在程序中是以流的形式来操作的。 + **输入流和输出流** ![28.Golang读取文件02.jpg](https://lilinchao.com/usr/uploads/2022/07/3522567276.jpg) + **流**:数据在数据源(文件)和程序(内存)之间经历的路径 + **输入流**:数据从数据源(文件)到程序(内存)的路径 + **输出流**:数据从程序(内存)到数据源(文件)的路径 ### 二、读取文件操作 #### 2.1 打开和关闭文件 + **打开文件** ```go func Open(filename string) (file *File, err error) ``` Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有`O_RDONLY`模式。如果出错,错误底层类型是`*PathError`。 + **关闭文件** ```go func (f *File) Close() error ``` Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。 **示例** ```go package main import ( "fmt" "os" ) func main() { //只读方式打开当前目录下的test.txt file, err := os.Open("test.txt") if err != nil { fmt.Println("open file failed!,err:",err) } //返回的是一个指针 fmt.Println(&file) //关闭文件 //err = file.Close() //if err != nil{ // fmt.Println("close file failed!,err:",err) //} //为了防止文件忘记关闭,通常使用defer注册文件关闭语句。 defer file.Close() // 关闭文件 } ``` **运行结果** ``` 0xc0000ce018 ``` ##### defer 语句 + `defer`—般用于资源的释放和异常的捕捉。 + `defer`语句会将其后面跟随的语句进行`延迟处理`;跟在`defer`后面的语言将会在程序进行最后的`return`之后再执行。 + 在`defer`归属的函数即将返回时,将延迟处理的语句按`defer`的逆序进行执行,也就是说,先被`defer`的语句最后被执行,最后被 `defer`的语句,最先被执行。 #### 2.2 file.Read() 读取文件 + ##### **Read 方法定义** ```go func (f *File) Read(b []byte) (n int, err error) ``` 从文件对象中读取长度为b的字节,返回当前读到的字节数以及错误信息。因此使用该方法需要先初始化一个符合内容大小的空的字节列表。读取到文件的末尾时,该方法返回0,`io.EOF`。 + ##### **ReadAt方法定义** ```go func (file *File) ReadAt(b []byte, off int64) (n int, err Error) ``` + **b**:是指定字节长度的缓冲区 + **off**:int64类型的偏移量,从此位置开始读取。 从文件的off偏移量开始读取长度为b的字节。返回读取到字节数以及错误信息。当读取到的字节数n小于想要读取字节的长度`len(b)`的时候,该方法将返回非空的error。当读到文件末尾时,err返回io.EOF。 *注意:ReadAt 绝对不允许出现,没有读满 buffer,又非 EOF,又没有 err 的情况发生,这个是接口语义明确规定的,这是一个非常细节的区别。* + ##### **一次性读取** 适用于读取较小文件使用 ```go package main import ( "fmt" "io" "os" ) func main() { //1、只读方式打开当前目录下的test2.txt file, err := os.Open("test2.txt") if err != nil { fmt.Println("open file failed!,err:",err) return } //3、当函数退出时,及时关闭file //使用 defer 内置函数 当函数退出时才会调用,要及时关闭否则会内存泄露 defer file.Close() //2、使用Read方法读取数据,注意一次只会读取128个字节 tmp := make([]byte, 128) n, err := file.Read(tmp) //使用ReadAt方法读取数据,注意一次只会读取6个字节 //tmp := make([]byte, 6) //n, err := file.ReadAt(tmp,6) //io.EOF 表示文件的末尾 if err == io.EOF { fmt.Println("文件读取完毕") return } if err != nil { fmt.Println("read file failed,err:",err) return } fmt.Printf("读取了 %d 字节数据\n", n) fmt.Println(string(tmp[:n])) } ``` **运行结果** ``` 读取了 13 字节数据 Hello Golang! ``` + ##### **循环读取** 使用 for 循环读取文件中的所有数据 ```go package main import ( "fmt" "io" "os" ) //循环读取文件 func main() { //只读方式打开当前目录下的test.txt file, err := os.Open("test.txt") if err != nil { fmt.Println("open file failed!,err:",err) return } //关闭文件 defer file.Close() //循环读取文件 var content []byte //使用Read方法读取数据,注意一次只会读取128个字节 tmp := make([]byte, 128) for { n, err := file.Read(tmp) //每次读取128个字节 if err == io.EOF { fmt.Println("文件读取完毕") break } if err != nil { fmt.Println("read file failed,err:",err) return } //每次读取的内容都追加到已知的byte切片中 content = append(content,tmp[:n]...) } //将byte类型转换结果,打印结果 fmt.Println(string(content)) } ``` **运行结果** ``` 文件读取完毕 水陆草木之花,可爱者甚蕃。晋陶渊明独爱菊。自李唐来,世人甚爱牡丹。 予独爱莲之出淤泥而不染,濯清涟而不妖,中通外直,不蔓不枝,香远益清,亭亭净植,可远观而不可亵玩焉。 予谓菊,花之隐逸者也;牡丹,花之富贵者也;莲,花之君子者也。 噫!菊之爱,陶后鲜有闻。莲之爱,同予者何人?牡丹之爱,宜乎众矣! ``` **说明** 这里的循环读取文件其实就是一个不断追加的过程,将每次读取的128个字节追加到预先定义好的content切片中,最后将切片转换成string类型,进行打印显示。 #### 2.3 bufio 读取文件 + **语法** ```go //bufio.NewReader(rd io.Reader) *Reader r := bufio.NewReader(file) //func (b *Reader) ReadString(delim byte) (string, error) n, err := r.Read(buf) ``` **参数** + **file**:要读取的文件句柄; + **buf**:读取的数据存放的缓冲区。 **返回值** + **n**:读取到的长度 + **err**:读取失败,则返回错误信息。 使用 NewReader 读取文件时,首先,需要打开文件,接着, 使用打开的文件返回的文件句柄当作 **函数参数** 传入 NewReader。 最后,使用 NewReader 返回的 reader 对象调用 Read 来读取文件。文件读取结束的标志是返回的 n 等于 0,因此,如果需要读取整个文件内容,那么我们需要使用 **for 循环** 不停的读取文件,直到 n 等于 0。 **示例** ```go package main import ( "bufio" "fmt" "io" "os" ) //bufio读取文件 func main() { //只读方式打开当前目录下的test.txt file, err := os.Open("test.txt") if err != nil { fmt.Println("open file failed!,err:",err) return } //关闭文件,避免内存泄露 defer file.Close() //通过bufio缓冲区读取文件 reader := bufio.NewReader(file) //建立缓冲区,将文件内容放入到缓冲区 //循环读取文件信息 for { line, err := reader.ReadString('\n') //读到一个换行就结束 if err == io.EOF { //io.EOF 表示文件的末尾 //输出最后的内容 if len(line) != 0 { fmt.Println(line) } fmt.Println("文件读取完毕") break } if err != nil { fmt.Println("read file failed,err:",err) return } fmt.Println(line) } } ``` **运行结果** ```go 水陆草木之花,可爱者甚蕃。晋陶渊明独爱菊。自李唐来,世人甚爱牡丹。 予独爱莲之出淤泥而不染,濯清涟而不妖,中通外直,不蔓不枝,香远益清,亭亭净植,可远观而不可亵玩焉。 予谓菊,花之隐逸者也;牡丹,花之富贵者也;莲,花之君子者也。 噫!菊之爱,陶后鲜有闻。莲之爱,同予者何人?牡丹之爱,宜乎众矣! 文件读取完毕 ``` #### 2.4 ioutil 读取文件 **语法** ```go func ReadFile(name string) ([]byte, error) ``` + **name**:文件路径地址 使用 `io/ioutil.ReadFile` 方法一次性将文件读取到内存中,只需要将文件名作为参数传入。 **示例** ```go package main import ( "fmt" "io/ioutil" ) //ioutil 读取整个文件 func main() { content, err := ioutil.ReadFile("test.txt") if err != nil { fmt.Println("read failed,err:",err) return } fmt.Println(string(content)) } ``` **运行结果** ``` 水陆草木之花,可爱者甚蕃。晋陶渊明独爱菊。自李唐来,世人甚爱牡丹。 予独爱莲之出淤泥而不染,濯清涟而不妖,中通外直,不蔓不枝,香远益清,亭亭净植,可远观而不可亵玩焉。 予谓菊,花之隐逸者也;牡丹,花之富贵者也;莲,花之君子者也。 噫!菊之爱,陶后鲜有闻。莲之爱,同予者何人?牡丹之爱,宜乎众矣! ``` *注意:如果文件比较大,一次性读取整个文件会占用很大的内存,影响执行效率。* *建议读取小文件时使用,不太适用于大文件的读取。* ### 三、效率比较 - **当文件较小(KB 级别)时,ioutil > bufio > file.Read()。** - **当文件大小比较常规(MB 级别)时,三者差别不大,但 bufio 优势已经显现出来。** - **当文件较大(GB 级别)时,bufio > file.Read()> ioutil。** **总结** 当读取小文件时,使用`ioutil`效率明显优于`file.Read()`和`bufio`,但如果是大文件,`bufio`读取会更快,效率更高。 *附参考文章链接* *https://www.cnblogs.com/KylinBlog/p/13607284.html* https://blog.csdn.net/weixin_28881575/article/details/112571155
标签:
Golang基础
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2263.html
上一篇
27.Golang之反射三定律
下一篇
29.Golang写入文件
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
2
标签云
Netty
Yarn
线程池
NIO
Ubuntu
Linux
Flume
哈希表
JavaWEB项目搭建
Spark Core
VUE
Spark SQL
锁
高并发
HDFS
JavaSE
MyBatisX
容器深入研究
nginx
DataX
查找
LeetCode刷题
Beego
链表
Shiro
队列
MyBatis
Zookeeper
JavaWeb
字符串
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭