Go的文件操作小结
文件是什么
计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件(以ASCII码存储的文件)和二进制文件(包含其他数据的文件),文本文件后缀通常是.txt,二进制文件有.bat,.bin,.exe等等
io和Reader及Writer接口
.什么是io,在计算机中指的是input/output,由于程序运行时数据是在内存中驻留的,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘,网络等。就需要IO接口
我们看到的io接口是这样的
Reader接口
type Reader interface {
Read (p [] byte ) (n int ,err error)
}
无论是什么包的Reader接口中都会有一个read方法,我们看无论什么包里的read方法,会发现传参是[]byte类型,之后read方法会流式读取文件中的数据,如果文件够大时 看,每个读取的字符个数就是我们的切片容量。
栗子:
func main() {
reader := strings.NewReader("Clear is better than clever")
ReadStr(reader)
}
func ReadStr(reader io.Reader) {
p := make([]byte, 4)
for {
n, err := reader.Read(p)
if err != nil {
if err == io.EOF {
fmt.Println("EOF:", n)
break
}
fmt.Println(err)
os.Exit(1)
}
fmt.Println(n, string(p[:n]))
}
} //通过strings包里的NewReader(string)创建一个字符串读取器,然后流式读取
Writer接口
type Writer interface {
Write (p []byte) (n int,err error)
}
write将len个字符从切片写到基本数据流中
栗子:
func main() {
proverbs := []string{
"Channels orchestrate mutexes serialize\n",
"Cgo is not Go\n",
"Errors are values\n",
"Don't panic\n",
}
var writer bytes.Buffer
for _, p := range proverbs {
n, err := writer.Write([]byte(p))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if n != len(p) {
fmt.Println("failed to write data")
os.Exit(1)
}
}
fmt.Println(writer.String())
}
bufio缓存io
bufio包实现了缓存io,它包装了io.Reader和io.Writer对象,创建了另外的Reader和Writer对象,他们也实现 了io.Reader接口,不过是有缓存的。
栗子:
func main() {
var str string
reader := bufio.NewReader(os.Stdin)
fmt.Println("Please input:")
str, err := reader.ReadString('\n')
if err == nil {
fmt.Println(str)
}
}
os.File
该类型表示本地系统上的文件,它实现了io.Reader和io.Writer,因此可以在任何流IO上下文中使用,
其中os.File,即文件类型中蕴含的fileperm表示了文件权限
如:
0777 //-rwxrwxrwx 所有人都可读、写、执行
0666 //-rw-rw-rw 所有人都可读,写,但不可执行
0644 //-rw-r-r 所有者有读写权限,用户组和其他人只能够读
下面是一个将字符串切片写入文件中的栗子
package main
import (
"fmt"
"os"
)
func main() {
proverbs := []string{
"Channels orchestrate mutexes serialize\n",
"Cgo is not Go\n",
"Errors are values\n",
"Don't panic\n",
}
file, err := os.Create("./proverbs.txt")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close()
for _, p := range proverbs {
n, err := file.Write([]byte(p))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if n != len(p) {
fmt.Println("failed to write data")
os.Exit(1)
}
}
fmt.Println("file write done")
}
打开文件和关闭文件
func main() {
//以只读方式打开当前目录下的open.go文件
file,err:=os.Open("./open.go")
if err!=nil {
fmt.Println("open file failed,err:",err)
return
}
//关闭文件
defer file.Close()
}
标准输入输出
Standard output input and error ,os包中公开三个变量,os.Stdout,os.Stdin,os.Stderr,他们的类型为os* *file,分别表示操作系统标准输出\输入和错误的文件句柄
下面是一个将字符串直接打印到标准输出的栗子
package main
import (
"fmt"
"os"
)
func main() {
proverbs := []string{
"Channels orchestrate mutexes serialize\n",
"Cgo is not Go\n",
"Errors are values\n",
"Don't panic\n",
}
for _, p := range proverbs {
n, err := os.Stdout.Write([]byte(p))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if n != len(p) {
fmt.Println("failed to write data")
os.Exit(1)
}
}
}
读取文件
file.Read()
func main() {
//Read方法定义如下:fun (f *file) Read(b [] byte) (n int,err error) 接收一个字符切片,返回读取的字节数和错误。
//读到文件末尾时会返回0和EOF
file,err:=os.Open("./open.go")
if err!=nil {
fmt.Println("open file failed,err:",err)
return
}
defer file.Close()
tmp:=make([]byte,128)
_,err=file.Read(tmp)
if err==io.EOF {
fmt.Println("finish read")
return
}
if err!=nil {
fmt.Println("failed to read,err",err)
return
}
fmt.Println(tmp[:]) //这么读取打印的是字符的ascii编码
fmt.Println(string(tmp)) //这样才是字符串
}
//当文件足够小的时候,128字节切片能够读完
//如果文件很大,那么就循环读取
func main() {
// 只读方式打开当前目录下的main.go文件
file, err := os.Open("./main.go")
if err != nil {
fmt.Println("open file failed!, err:", err)
return
}
defer file.Close()
// 循环读取文件
var content []byte
var tmp = make([]byte, 128)
for {
n, err := file.Read(tmp)
if err == io.EOF {
fmt.Println("文件读完了")
break //EOF这种情况必须在nil之前,因为最后一次读取是会读到文件末尾的,err=EOF
}
if err != nil {
fmt.Println("read file failed, err:", err)
return
}
content = append(content, tmp[:n]...)
}
fmt.Println(string(content))
}
bufio.NewReader()
func main() {
//bufio是封装过后的缓冲区文件操作
file,err:=os.Open("./open.go")
if err!=nil {
fmt.Println("open file failed,err:",err)
return
}
defer file.Close()
reader:=bufio.NewReader(file) //传入文件句柄 返回Reader结构体
for {
line, err := reader.ReadString('\n') //读到这个字符就进行换行
if err == io.EOF {
if len(line) != 0 {
fmt.Println(line) //如果没有这个判断语句 那么文件的最后一条字符串就无法读入
}
fmt.Println("finish read")
break
}
if err != nil {
fmt.Println("read file failed,err:",err)
return
}
fmt.Println(line)
}
}
写入文件
os.OpenFile()
os.OpenFile()函数能够以指定模式打开文件,从而实现文件写入相关功能
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
...
}
其中:
name:要打开的文件名 flag:打开文件的模式 perm:文件权限
os.O_WRONLY | 只写 |
---|---|
os.O_CREATE | 创建文件 |
os.O_RDONLY | 只读 |
os.O_RDWR | 读写 |
os.O_TRUNC | 清空 |
os.O_APPEND | 追加 |
追加模式:只能写不能读,写一个已经存在的文件,会在文件的后面写内容,追加一个不存在的文件,会先清空文件内容再写
清空模式:一个文件如果存在,且为只读或者只写成功打开,就将其长度截短为0
perm:文件权限,一个八进制数。r(读)04,w(写)02,x(执行)01
Write和WriteString
栗子:
func main() {
f,err:=os.OpenFile("./log.txt",os.O_CREATE|os.O_APPEND,0644)
if err!=nil {
fmt.Println("failed to open file ,err:",err)
return
}
defer f.Close()
str:="hello xiaocheng"
f.Write([]byte(str))
f.WriteString("wo ai xiaohuang")
}
bufio.NewWriter
func main() {
f,err:=os.OpenFile("./log.txt",os.O_APPEND,0644)
if err!=nil {
fmt.Println("failed to open file,err:",err)
return
}
defer f.Close()
writer:=bufio.NewWriter(f)
for i:=0;i<10;i++ {
writer.WriteString("我爱小黄") //将字符串写进缓存中
}
writer.Flush() //将缓存中的字符串写到文件中
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现