Go 运行中的数据保存在内存中。如果希望数据长久的保存在电脑中,这就需要使用 Go 生成文件,添加数据了。
创建文件
GO语言中提供了一个Create( )
函数专门创建文件。该函数在创建文件时,首先会判断要创建的文件是否存在,如果不存在,则创建,如果存在,会先将文件中已有的数据清空。
同时,当文件创建成功后默认会打开文件,所以不用再执行打开操作,可以直接向该文件中写入数据。
import "os"
func CreateFile(path string) {
// 创建文件,返回两个值
// 一个是创建的文件,另一个是错误信息
f, er := os.Create(path)
// 如果有错误,打印错误信息
if err != null {
fmt.Println("err=", err)
return
}
defer f.Close() // 退出整个函数时关闭文件
}
func main() {
var filePath = "a.txt"
CreateFile(filePath)
}
注意:在创建的文件时,注意需要判断是否出现异常,同时要注意defer
的应用
写入数据
文件打开以后,可以向文件中写数据,可以使用WriteString( )方法。
func CreateFile(path string) {
// 创建文件,返回两个值
// 一个是创建的文件,另一个是错误信息
f, er := os.Create(path)
// 如果有错误,打印错误信息
if err != null {
fmt.Println("err=", err)
return
}
for i := 1; i < 10; i++ {
// 写入文件
f.WriteString("Hello World!")
}
defer f.Close() // 退出整个函数时关闭文件
}
WriteString( )
方法默认返回两个参数
- 第一个参数,返回写入数据长度
- 第二个参数,错误信息
n, err := f.WriteString("Hello World!")
if err != nil {
fmt.Println(err)
}
fmt.Println(n)
WriteString( )
方法默认写到文件中的数据是不换行的。如果想换行,可以采用如下的方式
var str string
for i := 1; i < 10; i++ {
// 写入文件
str = fmt.Sprintf("i = %d\n", i)
n, err := f.WriteString(str)
if err != nil {
fmt.Println(err)
}
fmt.Println(n)
}
除了使用 WriteString( )
函数向文件中写入数据意外,还可以使用Write( )
函数
var str string
for i := 1; i < 10; i++ {
// 写入文件
str = fmt.Sprintf("i = %d\n", i)
buf := []byte(str)
n, err := f.Write(buf)
if err != nil {
fmt.Println(err)
}
fmt.Println(n)
}
注意:使用Write()
函数写数据时,参数为字节数组,所以需要将字符串转换成字节数组。该方法返回的也是写入文件数据的长度
第三种写入的方式使用 WriteAt()
函数,在指定的位置写入数据
var str string
var a int
for i := 1; i < 10; i++ {
// 写入文件
str = fmt.Sprintf("i = %d\n", i)
buf := []byte(str)
// 查找文件末尾偏移量
n, _ := f.Seek(0, os.SEEK_END)
// 从末尾偏移量开始写入内容
a, err := f.WriteAt([]byte(buf), n)
fmt.Println(a)
}
Seek()
函数返回值存储到变量n中,值为文件末尾的位置。WriteAt()
也返回的是写入的数据长度。
打开文件
Create()
函数,有两个作用:第一:创建新文件。第二:如果所创建的文件已经存在,会删除掉文件中存储的数据。为了保存原数据,对已经存在的文件不能再执行 Create()
,而是要执行 OpenFile()
。
func WriteFile(path string) {
// 打开文件
f, err := os.OpenFile(path, os.O_APPEND, 6)
if err != nil {
fmt.Println("err = ", err)
return
}
n, err1 := f.WriteString("Hello World")
if err1 != nil {
fmt.Println(err1)
return
}
fmt.Println(n)
// 关闭文件
defer f.Close()
}
OpenFile( )
函数有三个参数
-
第一个参数表示打开文件的路径
-
第二个参数表示模式,常见的模式有
O_RDONLY
(只读模式)O_WRONLY
(只写模式),O_RDWR
( 可读可写模式)O_APPEND
(追加模式)。
-
第三个参数,表示权限,取值范围(0-7)表示如下:
- 0:没有任何权限
- 1:执行权限 x(如果是可执行文件,是可以运行的)
- 2:写权限 r
- 3:写权限与执行权限 xr
- 4:读权限 w
- 5:读权限与执行权限 xw
- 6:读权限与写权限 wr
- 7:读权限,写权限,执行权限 xwr
读取文件
如果文件已经存在,并且也已经有数据了,那么可以直接读取该文件中的内容。读取文件中的数据,使用的是Read 函数
func ReadFile(filePath string) {
// 打开文件
f, err := os.Open(filePath)
if err != nil {
fmt.Println("err = ", err)
return
}
// 关闭文件
defer f.Close()
buf := make([]byte, 1024 * 2) // 2k大小
// n 代表从文件读取内容长度
n, err1 := f.Read(buf)
if err1 != nil && err1 != io.EOF {
// 文件出错,同时没到结尾
fmt.Println("err1 = ", err1)
return
}
fmt.Println("buf = ", string(buf[:n]))
}
Open()
是打开文件,与OpenFile()
的区别是,Open()
只有读的权限。
在使用Read()
函数读取文件中的内容时,需要一个切片类型,而定义切片时类型为字符数组,将文件中的内容保存在切片中,同时除了对其判断是否出错时以外,还要判断是否到文件末尾(这里需要导入io包)。
按行读取
Read()
是将文件的内容全部读取出来,然后存放在切片中,我们也可以每次只读取一行数据。这需要用到bufio包中的 ReadBytes函数
。
在使用 ReadBytes()
函数读取数据时,需要用到缓冲区,所谓缓冲区就是存储数据的区域,也就是先将从文件中读取的数据存储在该区域内,然后在将区域中的数据取出来,写到磁盘上。
提供缓冲区的原因是:为了缓和 CPU 与 磁盘设备之间速度不匹配矛盾。文件缓冲区是用以暂时存放读写期间的文件数据而在内存区预留的一定空间。
func ReadLine(path) {
// 打开文件
f, err := os.Open(path)
if err != nil {
fmt.Println("err = ", err)
return
}
// 关闭文件
defer f.Close()
// 创建缓冲区
r := bufio.NewReader(f)
// 循环读取文件内容,直到文件末尾
for {
// 遇到`\n`结束读取,但`\n`也读取进入
buf, err != r.ReadBytes('\n')
if err != nil {
if err == io.EOF {
// 文件已经结束
break
}
fmt.Println("err = ", err)
}
fmt.Printf("buf = #%s#\n", string(buf))
}
}
在使用 ReadBytes()
函数时,传递的参数是‘\n’,表示遇到’\n’就结束,所以使用了死循环(每循环一次,读取一行数据),只有到文件末尾了,才退出整个循环。最后,将读取的数据打印出来,注意ReadBytes( )返回的是字节切片,所以在打印时要转换成字符串。
相对路径,所谓相对路径指的是文件相对于应用程序的路径。
绝对路径:指的是通过给定的这个路径直接能在我的电脑中找到这个文件。例如:D:\StudentInfo.txt
操作案例
实现文件拷贝,将已有的文件复制一份,同时重新命名。
func main() {
var srcFileName string // 源文件
var dstFileName string // 目标文件
fmt.Printf("请输入源文件名称:")
fmt.Scan(&srcFileName)
fmt.Println("请输入目的文件名称:")
fmt.Scan(&dstFileName)
if srcFileName == dstFileName {
fmt.Println("源文件和目的文件名字不能相同")
return
}
//只读方式打开源文件
sF, err1 := os.Open(srcFileName)
if err1 != nil {
fmt.Println("err1 = ", err1)
return
}
//新建目的文件
dF, err2 := os.Create(dstFileName)
if err2 != nil {
fmt.Println("err2 = ", err2)
return
}
//操作完毕,需要关闭文件
defer sF.Close()
defer dF.Close()
//核心处理,从源文件读取内容,往目的文件写,读多少写多少
buf := make([]byte, 4*1024) //4k大小临时缓冲区
for {
n, err := sF.Read(buf) //从源文件读取内容,每次读取一部分
if err != nil {
fmt.Println("err = ", err)
if err == io.EOF { //文件读取完毕
break
}
}
//往目的文件写,读多少写多少
dF.Write(buf[:n])
}
}