Golang文件读写操作详情
来源:脚本之家
时间:2022-12-27 17:21:08 426浏览 收藏
本篇文章给大家分享《Golang文件读写操作详情》,覆盖了Golang的常见基础知识,其实一个语言的全部知识点一篇文章是不可能说完的,但希望通过这些问题,让读者对自己的掌握程度有一定的认识(B 数),从而弥补自己的不足,更好的掌握它。
一、概念
文件是数据源(保存数据的地方)的一种,文件最主要的作用就是保存数据。
文件在程序中是以流的形式来操作的。
- 输入流和输出流
- 流:数据在数据源(文件)和程序(内存)之间经历的路径
- 输入流:数据从数据源(文件)到程序(内存)的路径
- 输出流:数据从程序(内存)到数据源(文件)的路径
二、读取文件操作
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 | 打开时清空文件原先内容 |
os.O_APPEND | 追加 |
若同时想用多种可用|
拼接不同模式。
文件权限perm:
使用4位8进制数
来表示三种类型用户的权限,首位取0,形式即0XXX
。
- 第一个X表示的是文件所有者的权限;
- 第二个X表示的是组用户的权限;
- 第三个X表示的是其他用户的权限。
每位数字所代表的权限:读r=4,写w=2,可执行x=1
数字 | r | w | x | 权限 |
---|---|---|---|---|
0 | - | - | - | 所有权限均无 |
1 | - | - | x | 可执行 |
2 | - | w | - | 可写 |
3 | - | w | x | 可写,可执行 |
4 | r | - | - | 可读 |
5 | r | - | x | 可读,可执行 |
6 | r | w | - | 可读,可写 |
7 | r | w | x | 可读,可写,可执行 |
常使用的0644
(-rw-r--r--
),表示文件所有者可读写,同组用户及其他用户只可读。
3.2 Write和WriteString 方式写入
Write语法:
func (file *File) Write(b []byte) (n int, err Error)
参数
返回值:
使用 Write 方法写文件,接受的 参数 是一个要写入的文件内容的 字节 数组。如果写入成功,返回成功写入的字节数,如果写入失败,返回 error 信息。
WriteString语法:
func (f *File) WriteString(s string) (n int, err error)
参数
返回值:
使用 WriteString 方法写文件,接受的参数是一个要写入的文件内容的 字符串。如果写入成功,返回成功写入的字节数,如果写入失败,返回 error 信息。
- file:文件对象
- b:要写入的文件内容
- n: 成功写入的字节数
- err:写入失败,则返回错误信息
- f:文件对象
- s:要写入的文件内容
- n:成功写入的字节数
- err:写入失败,则返回错误信息
示例:
package main import ( "fmt" "os" ) //创建并写入数据 //Write 和 WriteString func main() { //os.O_CREATE|os.O_RDWR:如果不存在文件,创建文件,可读可写 //0666对应:-rw-rw-rw- file, err := os.OpenFile("D:/bb.txt", os.O_CREATE|os.O_RDWR, 0666) if err != nil { fmt.Println("open file failed,err:",err) return } defer file.Close() str := "Hello Golang\r\n" file.Write([]byte(str)) //写入字节切片数据 file.WriteString("直接写入的字符串数据") //直接写入字符串数据 }
3.3 bufio.NewWriter
语法:
func NewWriter(w io.Writer) *Writer
func (b *Writer) WriteString(s string) (int, error)
func (b *Writer) Flush() error
将要写入的内容写入缓存中,在执行flush的时候才会被写到磁盘。
- 创建writer实例
- 将信息写入缓存
- 将缓冲写入文件
示例:
package main import ( "bufio" "fmt" "os" ) //bufio.NewWriter func main() { //1、打开文件 file,err := os.OpenFile("D:/cc.txt",os.O_CREATE|os.O_TRUNC|os.O_WRONLY,0666) if err != nil { fmt.Println("open file failed,err:",err) return } //5、关闭文件流 defer file.Close() //2、创建writer对象 writer := bufio.NewWriter(file) for i := 0; i3.4 ioutil.WriteFile
语法:
func WriteFile(filename string, data []byte, perm os.FileMode) error参数
返回值
使用 WriteFile 方法写文件,接受的第一个 参数 是一个 string 类型 的文件名,第二个参数是一个要写入的文件内容的 byte 数组,最后一个参数是文件的权限。如果写入成功,返回空的 error 信息,如果写入失败,返回 error 信息。
- filename:文件路径+文件名称
- data:要写入的文件内容
- perm:文件权限
- err:写入失败,则返回错误信息
示例:
package main import ( "fmt" "io/ioutil" ) //ioutil.WriteFile func main() { str := "Hello Golang" err := ioutil.WriteFile("D:/dd.txt", []byte(str), 0666) if err != nil { fmt.Println("write file failed,err:",err) return } }
四、复制文件
4.1 通过ioutil进行复制
package main import ( "fmt" "io/ioutil" ) //复制文件 //ioutil 进行复制 //编写一个函数,接收两个文件路径 srcFileName dstFileName func CopyFile(srcFileName string,dstFileName string)(err error){ input, err := ioutil.ReadFile(srcFileName) if err != nil { fmt.Println(err) return err } err = ioutil.WriteFile(dstFileName, input, 0644) if err != nil { fmt.Println("Error creating",dstFileName) fmt.Println(err) return err } return nil } func main() { srcFile := "D:/aa.zip" dstFile := "D:/bb.zip" err := CopyFile(srcFile, dstFile) if err == nil { fmt.Printf("拷贝完成\n") }else { fmt.Printf("拷贝错误 err=%v\n",err) } }
4.2 以文件流的方式复制文件
package main import ( "fmt" "io" "os" ) //复制数据 func CopyFile(srcFileName string,dstFileName string)(err error){ source, _ := os.Open(srcFileName) destination, _ := os.OpenFile(dstFileName, os.O_CREATE|os.O_WRONLY, 0666) buf := make([]byte, 128) for { n, err := source.Read(buf) if err != nil && err != io.EOF { return err } if n == 0 { break } if _,err := destination.Write(buf[:n]); err != nil { return err } } return nil } func main() { srcFile := "D:/aa.zip" dstFile := "D:/bb.zip" err := CopyFile(srcFile, dstFile) if err == nil { fmt.Printf("拷贝完成\n") }else { fmt.Printf("拷贝错误 err=%v\n",err) } }
五、其他操作
package main import ( "fmt" "os" ) func main() { //文件重命名 err01 := os.Rename("D:/aa.txt","D:/ee.txt") //只能同盘操作 if err01 != nil { fmt.Println(err01) } //创建目录 err02 := os.Mkdir("D:/aa", 0666) if err02 != nil { fmt.Println(err02) } //一次创建多个目录 err03 := os.MkdirAll("D:/aa/bb/cc",0666) //创建多级目录 if err03 != nil { fmt.Println(err03) } //删除目录和文件 err04 := os.Remove("D:/ee.txt") if err04 != nil { fmt.Println(err04) } //一次删除多个目录或者文件 err05 := os.RemoveAll("D:/aa") if err05 != nil { fmt.Println(err05) } }
今天关于《Golang文件读写操作详情》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于golang的内容请关注golang学习网公众号!
-
140 收藏
-
202 收藏
-
400 收藏
-
426 收藏
-
235 收藏
-
233 收藏
-
322 收藏
-
181 收藏
-
316 收藏
-
244 收藏
-
300 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习