Go 文件读取和写入操作全面讲解
Go 文件的读取操作
os 包 和 bufio 包
Go 标准库的 os
包,为我们提供很多操作文件的函数,如 Open(name)
打开文件、Create(name)
创建文件等函数,与之对应的是 bufio
包,os
包是直接对磁盘进行操作的,而 bufio
包则是带有缓冲的操作,不用每次都去操作磁盘。
os.Open 与 os.OpenFile 以及 File.Read
Open(name string) (*File, error)
通过 文件名 或 文件路径+文件名 的形式打开一个文件,此文件只能用于读操作,如果文件不存在则返回
PathError
。- 参数
name
为文件名或文件路径+文件名。 - 返回值
*File
为一个File
结构体的指针类型,通过指针可以对文件进行读写等操作。
- 参数
返回值
`error` 为打开文件的过程中产生的错误。
OpenFile(name string, flag int, perm FileMode) (*File, error)
通过指定 文件名 或 文件路径+文件名、文件操作模式、文件权限三个参数打开一个文件,之后可对此文件进行读写操作。
- 参数
name
为文件名或文件路径+文件名。 - 参数
flag
为指定文件操作模式,可选值有O_RDONLY
→ 只读操作、O_WRONLY
→ 只写操作、O_RDWR
→ 读写操作、O_APPEND
→ 写入时向文件追加数据、O_CREATE
→ 如果不存在,则创建一个新文件等。 - 参数
perm
参数表示文件的模式和权限,例如0666
为读写权限。如果对文件权限所对应的数字不了解,可以去学习一下。 - 返回值
*File
为一个File
结构体的指针类型,通过指针可以对文件进行读写等操作。 - 返回值
error
为打开文件的过程中产生的错误。
File.Read(b []byte) (n int, err error)
读取与 b
等长度的字节,并存储到 b
里面。
- 参数
b
为一个切片数组,用于指定读取长度和存储字节数据。 - 返回值
n
为所读取字节的长度。 - 返回值
error
为读取字节的过程中产生的错误。
读取文件操作
import ( "fmt" "os" ) func main() { file, err := os.Open("1.txt") if err != nil { fmt.Println(err) return } defer file.Close() data := make([]byte, 11) count, err := file.Read(data) if err != nil { return } fmt.Println("字节数据:", data) // [72 101 108 108 111 32 119 111 114 108 100] fmt.Println("字符串数据:", string(data)) // Hello world fmt.Println("所获取字节的长度:", count) // 11 }
执行结果:
字节数据: [72 101 108 108 111 32 119 111 114 108 100]
字符串数据: Hello world
所获取字节的长度: 11
- 首先通过
Open
函数打开1.txt
文件,用file
变量接收,默认为可读模式; - 然后创建一个长度为
11
的字节切片,接着通过file
变量的方法Read
读取长度为11
的字节数据。os.Open("1.txt")
等价于os.OpenFile("1.txt", os.O_RDONLY, 0)
。 - 最后打印读取到的数据,文件操作完毕之后,需要关闭文件
file.Close()
。
bufio.NewReader 和 Reader.ReadString
读取文件,建议使用 bufio.NewReader
和 Reader.ReadString
,减少磁盘的操作。
NewReader(rd io.Reader) *Reader
获取一个有缓冲区的Reader
指针变量,缓冲区默认大小为4096
字节。通过变量可以对数据进行读操作。- 参数
rd
为一个接口,实现这个接口的数据类型变量都可以作为参数,例如上面提到的File
。 - 返回值
*Reader
为Reader
结构体的指针,通过指针可以读取缓冲区的数据。
- 参数
ReadString(delim byte) (string, error)
读取数据,直到第一次遇到分隔符delim
为止。读取过程中发生错误会返回EOF
错误信息。- 参数
delim
为分隔符,每次读取时遇到分隔符就会终止。 - 第一个返回值为所读取的内容,内容包括分隔符。
- 第二个返回值为读取过程中产生的错误信息。
- 参数
读取文件操作
1.txt
文件的内容为:
Hello world
Hello Golang
Hello Gopher
import ( "bufio" "fmt" "io" "os" "strings" ) func main() { file, err := os.OpenFile("1.txt", os.O_RDONLY, 0) if err != nil { fmt.Println(err) return } defer file.Close() reader := bufio.NewReader(file) for { if lineData, err := reader.ReadString('\n'); err != nil { if err == io.EOF { // 因为是以换行符为分隔符,如果最后一行没有换行符,那么返回 io.EOF 错误时,也是可能读到数据的,因此判断一下是否读到了数据 if len(lineData) > 0 { fmt.Println(lineData) } break } } else { fmt.Println(strings.TrimRight(lineData, "\n")) } } }
执行结果:
Hello World
Hello Golang
Hello Gopher
- 首先通过
OpenFile
函数打开1.txt
文件,用file
变量接收,指定为可读模式; - 然后通过
NewReader
函数创建一个缓冲区,将默认长度的字节读取到缓冲区中; - 接着通过
Reader
结构体的方法ReadString
,以\n
为分隔符,按行读取数据,然后打印数据。 - 其中有一个注意点就是,因为是以换行符为分隔符,如果最后一行没有换行符,那么返回
io.EOF
错误时,也是可能读到数据的,因此需要判断一下是否读到了数据。
Go 文件的写入操作
File.Write、File.WriteString、File.WriteAt
File.Write(b []byte) (n int, err error)
直接操作磁盘往文件里写入数据,写入单位为字节。
b
参数:写入的数据,类型为字节切片。- 返回值
n
:写入的字节数。 - 返回值
err
:写入数据的过程中产生的错误。
File.WriteString(s string) (n int, err error)
直接操作磁盘往指定文件里写入数据,写入单位为字符串。
s
参数:写入的字符串数据。- 返回值
n
:写入的字节数。 - 返回值
err
:写入数据的过程中产生的错误。
File.WriteAt(b []byte, off int64) (n int, err error)
从指定位置
off
往文件里顺序写入数据,如果某个偏移量上有数据,则会覆盖。b
参数:写入的数据,类型为字节切片。off
参数:偏移量,从此位置开始写入数据。- 返回值
n
:写入的字节数。 - 返回值
err
:写入数据的过程中产生的错误。
文件写入操作
import ( "fmt" "os" ) func main() { file, err := os.OpenFile("test.txt", os.O_CREATE, 0) if err != nil { fmt.Println(err) return } defer file.Close() count, err := file.Write([]byte{'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\n'}) if err != nil { return } fmt.Printf("写入了 %d 字节\n", count) count, err = file.WriteString("Hello Golang") if err != nil { return } fmt.Printf("写入了长度为 %d 的字符串\n", count) count, err = file.WriteAt([]byte{'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, 0) if err != nil { return } fmt.Printf("写入了 %d 字节\n", count) }
- 首先打开
test.txt
文件,指定的模式为os.O_CREATE
,如果文件不存在则会自动创建; - 然后通过
Write
方法以字符的形式往文件里写入Hello World\n
的内容;
接着通过 WriteString
方法以字符串的形式往文件里写入 Hello Golang
内容;此时文件里的内容如下所示:
Hello World
Hello Golang
最后通过 WriteAt
方法,指定从偏移量为 0
的位置开始写入数据 xxxxxxxxxxx
,由于 0
以及之后位置都有数据,因此原有数据被覆盖了。最后文件的内容为:
xxxxxxxxxxx
Hello Golang
File.Seek
File.Seek(offset int64, whence int)
相对于开头位置或当前位置或末尾位置,将设置当前读或写的偏移量设置为
offset
。offset
参数:所要设置的偏移量。whence
:相对于哪个位置开始设置偏移量的标志,可选值为0
→ 开头位置,1
→ 当前位置,2
→ 末尾位置。
应用
import ( "fmt" "os" ) func main() { file, err := os.OpenFile("test.txt", os.O_CREATE, 0) if err != nil { fmt.Println(err) return } defer file.Close() _, err = file.WriteString("G0lang") if err != nil { return } _, err = file.Seek(1, 0) if err != nil { fmt.Println(err) return } _, err = file.Write([]byte{'o'}) if err != nil { fmt.Println(err) return } }
- 打开
test.txt
文件,指定的模式为os.O_CREATE
,如果文件不存在则会自动创建; - 使用
WriteString
方法往文件里写入G0lang
字符串; - 此时发现第二个字符错了,
0
应该改成o
;此时的偏移量是指向尾部的;使用Seek
方法将偏移量移到第二个位置,然后写入字符o
,由于当前位置已有数据0
,因此o
将会覆盖0
;
bufio.NewWriter、Writer.WriteString、Writer.Flush
如果需要多次执行写入文件的操作,推荐使用 bufio
里的 Writer
结构体去操作,它会开辟一个缓冲区,默认大小为 4096
字节。在数据没有被刷入磁盘之前,所写入的数据都会暂时保存到缓冲区里。
NewWriter(w io.Writer) *Writer
开辟一个默认值为
4096
字节的缓冲区,用于暂存写入文件的数据内容,返回一个Writer
结构体的指针变量w
参数:类型为Writer
接口,实现这个接口的数据类型变量都可以作为参数,例如File
。- 返回值
*Writer
:一个Writer
结构体的指针变量,通过该变量可以往缓冲区里写入数据。
Writer.WriteString(s string) (int, error)
往缓冲区写入内容的方法。
- 参数
s
为写入的字符串。 - 第一个返回值为写入的字节数。
- 第二个返回值为写入数据的过程中产生的错误。
- 参数
Writer.Flush() error
将所有的缓存数据写入磁盘。
- 返回值为数据写入磁盘的过程中产生的错误。
文件写入操作
import ( "bufio" "fmt" "os" ) func main() { file, err := os.OpenFile("test.txt", os.O_CREATE, 0) if err != nil { fmt.Println(err) return } defer file.Close() writer := bufio.NewWriter(file) _, err = writer.WriteString("Hello World\n") if err != nil { fmt.Println(err) return } _, err = writer.WriteString("Hello Golang\n") if err != nil { fmt.Println(err) return } _, err = writer.WriteString("Hello Gopher\n") if err != nil { fmt.Println(err) return } writer.Flush() }
- 首先打开
test.txt
文件,指定的模式为os.O_CREATE
,如果文件不存在则会自动创建; - 然后使用
NewWriter
函数获取一个Writer
结构体的指针变量writer
; - 接着通过
writer
的WriteString
方法将内容保存到缓冲区里; - 最后调用
Flush
方法,将所有的缓存数据写入磁盘。
小结
文件的读取操作推荐 bufio
包里的 NewReader
函数和 Reader
结构体的方法 ReadString
,能减少对磁盘的操作,高效读取数据。
文件的写入操作推荐 bufio.NewWriter
、Writer.WriteString
、Writer.Flush
,使用它们代替 File 结构体里的写入方法,可以不用频繁操作磁盘,提高写入效率。
以上就是Go 文件读取和写入操作全面的详细内容,更多关于Go 文件的读取和写入操作的资料请关注脚本之家其它相关文章!
相关文章
详解Go语言如何实现类似Python中的with上下文管理器
熟悉 Python 的同学应该知道 Python 中的上下文管理器非常好用,那么在 Go 中是否也能实现上下文管理器呢,下面小编就来和大家仔细讲讲吧2023-07-07GoFrame gmap遍历hashmap listmap treemap使用技巧
这篇文章主要为大家介绍了GoFrame gmap遍历hashmap listmap treemap使用技巧的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-06-06
最新评论