基本介绍
文件是数据源,数据库也是一种特殊的文件。
Go语言中os.File结构体封装了文件的相关操作。
打开和关闭文件
-----打开文件-----
file, err := os.Open("D:/111.txt")
if err != nil{fmt.Println("err = ", err)
}此时file就是一个指针,不包括实际的file对象内容-----关闭文件-----
err = file.Close()
if err != nil{fmt.Println("Close err = ", err)
}
读取文件
第一种方式
适用于文件比较大的情况,带缓冲的读取文件。
使用bufio包。
-----打开文件-----
file, err := os.Open("D:/111.txt")
if err != nil{fmt.Println("err = ", err)
}
-----关闭文件-----
defer file.Close()
使用defer关闭file句柄,defer在函数最后执行-----读取文件-----
创建一个*reader 带缓冲的(内存和硬盘之间存在缓冲区,先放一块数据到缓冲区)
reader := bufio.NewReader(file)
循环读取文件内容
for{str, err := reader.ReadString("\n") //读到一个换行就结束,str中包括换行if err == io.EOF{ io.EOF代表文件结束break }fmt.Print(str)
}
fmt.Println("文件读取完成")
第二种方式
整个文件直接读入内存。适用于文件比较小的情况。
使用ioutil包。ioutil包目前已经被弃用。
package main
import("fmt""io/ioutil"
)func main(){file := "d:/test.txt"content, err := ioutil.ReadFile(file)if err != nil{fmt.Println("err = ", err)}fmt.Println(content)content是一个byte切片,因此需要转一下格式fmt.Println(string(content))
}
该方式不需要显式读取和关闭文件。
文件写入
bufio包中的Reader和Writer都是有缓冲的读写数据。
创建文件并进行写入
创建和读取文件使用os包,写入文件使用bufio包。
使用os.Openfile函数进行文件创建。
第一个参数是文件名。
第二个参数是包含以下选项。
第三个参数在linux系统下,win系统下无效,该参数是进行权限控制的。
package mainimport ("bufio""fmt""os"
)func main() {filePath := "d:/abc.txt"file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0666)if err != nil {fmt.Println("err = ", err)return}// 关闭文件句柄defer file.Close()writer := bufio.NewWriter(file)for i := 0; i < 5; i++ {writer.WriteString("hello,World!\n")}// WriterString带缓存区的写入// 因此需要writer.Flush()清空缓冲区,将内存写入硬盘writer.Flush()}
打开存在的文件并进行内容覆盖
file, err := os.OpenFile(filePath, os.O_TRUNC|os.O_WRONLY, 0666)
OpenFile函数中的第二个参数os.O_TRUNC代表追加;os.O_WRONLY代表写入。
打开存在文件进行文件追加
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0666)
os.O_APPEND代表追加。
打开存在文件将内容显示在终端,然后进行文件追加
初始化文件使用os包,读取文件内容使用bufio包,写入文件使用bufio包,
package mainimport ("bufio""fmt""io""os"
)func main() {filePath := "d:/abc.txt"file, err := os.OpenFile(filePath, os.O_APPEND|os.O_RDWR, 0666)if err != nil {fmt.Println("err = ", err)return}// 关闭文件句柄defer file.Close()// 读取原来的文件内容,并输出在终端reader := bufio.NewReader(file)for {str, err := reader.ReadString('\n')if err == io.EOF {break}fmt.Print(str)}// 追加写入writer := bufio.NewWriter(file)for i := 0; i < 5; i++ {writer.WriteString("11111\r\n")}// WriterString带缓存区的写入// 因此需要writer.Flush()清空缓冲区,将内存写入硬盘writer.Flush()}
将一个文件内容copy到另一个文件之中
读取文件、写入文件都使用os包。
package mainimport ("fmt""os"
)func main() {file1Path := "d:/abc.txt"file2Path := "e:/111.txt"// 读取源文件内容data, err := os.ReadFile(file1Path)if err != nil {fmt.Println("读取文件失败:", err)return}// 将内容写入目标文件err = os.WriteFile(file2Path, data, 0644)if err != nil {fmt.Println("写入文件失败:", err)return}fmt.Println("文件复制成功")
}
抛开错误处理,就两步,一个读,一个写。
判断文件是否存在
- 使用os.Star()函数判断是否存在。
import ("os""fmt"
)func checkExist(path string) {fileInfo, err := os.Stat(path)if err != nil {if os.IsNotExist(err) {fmt.Printf("路径 %q 不存在\n", path)} else {fmt.Printf("发生错误: %v\n", err)}return}if fileInfo.IsDir() {fmt.Printf("%q 是一个目录\n", path)} else {fmt.Printf("%q 是一个文件\n", path)}
}
os.Star(Path) 返回值:
- 如果成功:返回一个os.FileInfo接口,包含文件/目录的信息。
- 如果失败:返回一个非 nil 的 error。
判断是否存在的标准方式
if os.IsNotExist(err) {// 路径不存在
} else if err != nil {// 其他错误,比如权限不足
}
不能直接使用err == 进行判断,就使用os.IsNotExist()进行判断
后续使用中一般都是封装成函数进行使用。
文件操作编程实例
1. 编写一个函数,将一个图片拷贝到另一个文件夹中。
func CopyFile(src, dst string) {// 打开源文件srcFile, _ := os.Open(src)defer srcFile.Close()// 创建目标目录(如果不存在)os.MkdirAll(filepath.Dir(dst), 0755)// 创建目标文件dstFile, _ := os.Create(dst)defer dstFile.Close()// 拷贝内容io.Copy(dstFile, srcFile)
}
在这个例子中,srcFile和dstFiled都是*os.File类型
io.Copy()接受Writer和Reader接口类型,也就是说*os.File类型实现了io.Reader和io.Writer。直接使用没有问题。
2. 统计一个文件中含有多少英文、数字等信息
package mainimport ("bufio""fmt""io""os"
)type CharCount struct {ChCount int // 记录英文个数NumCount int // 记录数字的个数SpaceCount int // 记录空格的个数OtherCount int // 记录其他字符的个数
}func main() {filePath := "d:/abc.txt"file, err := os.Open(filePath)if err != nil {fmt.Println(err)return}defer file.Close()var count CharCount// 使用带缓冲的读取// bufio包中是带缓冲的读取,读取之前必须先拿到文件的句柄// os.ReadFile()函数不带缓冲读,不需要打开文件句柄,直接放入文件路径即可reader := bufio.NewReader(file)for {str, err := reader.ReadString('\n')if err == io.EOF {break}for _, v := range str {switch {case v >= 'a' && v <= 'z':fallthrough //穿透处理,直接进入到下一个casecase v >= 'A' && v <= 'Z':count.ChCount++case v == ' ' || v == '\t':count.SpaceCount++case v >= '0' && v <= '9':count.NumCount++default:count.OtherCount++}}}fmt.Println(count)
}