您现在的位置是:网站首页> 编程资料编程资料
Golang文件读写操作详情_Golang_
2023-05-26
414人已围观
简介 Golang文件读写操作详情_Golang_
一、概念
文件是数据源(保存数据的地方)的一种,文件最主要的作用就是保存数据。
文件在程序中是以流的形式来操作的。
- 输入流和输出流

- 流:数据在数据源(文件)和程序(内存)之间经历的路径
- 输入流:数据从数据源(文件)到程序(内存)的路径
- 输出流:数据从程序(内存)到数据源(文件)的路径
二、读取文件操作
2.1 打开和关闭文件
打开文件:
func Open(filename string) (file *File, err error)
Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。
关闭文件:
func (f *File) Close() error
Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。
示例:
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 方法定义
func (f *File) Read(b []byte) (n int, err error)
从文件对象中读取长度为b的字节,返回当前读到的字节数以及错误信息。因此使用该方法需要先初始化一个符合内容大小的空的字节列表。读取到文件的末尾时,该方法返回0,io.EOF。
ReadAt方法定义
func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
从文件的off偏移量开始读取长度为b的字节。返回读取到字节数以及错误信息。当读取到的字节数n小于想要读取字节的长度len(b)的时候,该方法将返回非空的error。当读到文件末尾时,err返回io.EOF。
- b:是指定字节长度的缓冲区
- off:int64类型的偏移量,从此位置开始读取。
注意:ReadAt 绝对不允许出现,没有读满 buffer,又非 EOF,又没有 err 的情况发生,这个是接口语义明确规定的,这是一个非常细节的区别。
一次性读取
适用于读取较小文件使用:
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 循环读取文件中的所有数据:
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 读取文件
语法:
//bufio.NewReader(rd io.Reader) *Reader r := bufio.NewReader(file) //func (b *Reader) ReadString(delim byte) (string, error) n, err := r.Read(buf)
参数
返回值:
使用 NewReader 读取文件时,首先,需要打开文件,接着, 使用打开的文件返回的文件句柄当作 函数参数 传入 NewReader。
最后,使用 NewReader 返回的 reader 对象调用 Read 来读取文件。文件读取结束的标志是返回的 n 等于 0,因此,如果需要读取整个文件内容,那么我们需要使用 for 循环 不停的读取文件,直到 n 等于 0。
- file:要读取的文件句柄;
- buf:读取的数据存放的缓冲区。
- n:读取到的长度
- err:读取失败,则返回错误信息。
示例:
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) } }运行结果:
水陆草木之花,可爱者甚蕃。晋陶渊明独爱菊。自李唐来,世人甚爱牡丹。
予独爱莲之出淤泥而不染,濯清涟而不妖,中通外直,不蔓不枝,香远益清,亭亭净植,可远观而不可亵玩焉。
予谓菊,花之隐逸者也;牡丹,花之富贵者也;莲,花之君子者也。
噫!菊之爱,陶后鲜有闻。莲之爱,同予者何人?牡丹之爱,宜乎众矣!
文件读取完毕
2.4 ioutil 读取文件
语法:
func ReadFile(name string) ([]byte, error)
- name:文件路径地址
使用 io/ioutil.ReadFile 方法一次性将文件读取到内存中,只需要将文件名作为参数传入。
示例:
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读取会更快,效率更高。
三、写入文件操作
3.1 os.OpenFile()函数
语法:
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
参数
os.OpenFile()函数能够以指定模式打开文件,从而实现文件写入相关功能。
- name:要文件路径+文件名;
- flag:打开文件的模式,只读、读写等;
- perm:文件权限,一个八进制数。r(读)04,W(写)02,x(执行)01。
模式flag种类:
| 模式 | 含义 |
|---|---|
| os.O_WRONLY | 只写 |
| os.O_CREATE | 如果不存在文件,创建文件 |
| os.O_RDONLY | 只读 |
| os.O_RDWR | 可读可写 |
| os.O_TRUNC | 打开时清空文件原先内容 |
