Go的Io流
获取文件信息
//获取文件
fileinfo, err := os.Stat("./aa.txt")//相对绝对路径都可以
if err != nil {
fmt.Println(err)
return
}
fmt.Println(fileinfo) //所有的信息都在其中
fmt.Println(fileinfo.Name()) //获取文件名称
fmt.Println(fileinfo.Mode()) //获取文件权限
fmt.Println(fileinfo.IsDir()) //判断文件是不是文件夹
fmt.Println(fileinfo.ModTime()) //获取文件修改时间
fmt.Println(fileinfo.Size()) //获取文件大小
fmt.Println(fileinfo.Sys()) //获取文件的系统属性
//不过此方法需要通过反射才能使用
文件权限表示
符号表示
type owner group others
type:文件类型 -文件 d文件夹
八进制表示
r 004 w 003 x 001 -000
777是最大权限
创建文件与目录
创建目录
//创建目录
err := os.Mkdir("d://a", os.ModePerm)
//mkdir不能创建多级目录 比如 "d://v//c" 若c前面的路径不存在就会报错
if err != nil {
fmt.Println(err)
return
}
fmt.Println("目录创建成功")
创建多级目录
//创建多级目录
err := os.MkdirAll("d://c//e//d", 777)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("创建成功")
删除文件
//remove只能删除空目录
err := os.Remove("d://c")
if err != nil {
fmt.Println(err)
fmt.Println("删除是吧")
//return
}
fmt.Println("删除成功")
//直接删除 不管该目录下是否有内容 慎用
err2 := os.RemoveAll("d://c")
if err2 != nil {
fmt.Println(err2)
fmt.Println("删除失败")
return
}
fmt.Println("删除成功")
创建文件
//创建文件 每次执行都会覆盖创建 内容也会空内容覆盖
file, err := os.Create("./bb.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(file.Name())
//删除文件
err=os.Remove("./bb.txt")
fmt.Println(err)
IO读取文件内容
获取文件连接有两种方式
//1.获取文件对象 建立连接 第一种方式
file, err := os.Open("./aa.txt")
if err != nil {
fmt.Println(err)
return
}
//2.关闭连接
defer file.Close() //使用defer 使得程序全部运行完毕再关闭
//第二种这种建立连接方式 可以指定权限 打开模式方式 这样就可以操作文件的更多细节
//openfile(文件路径,文件可操作动作,文件权限)
file2, err2 := os.OpenFile("./aa.txt", os.O_RDONLY|os.O_WRONLY, os.ModePerm)
if err2 != nil {
fmt.Println(err2)
return
}
//若以及确定文本本身的权限足够 比如已经可读可写 就不用此种方式建立文件连接了
//关闭连接
defer file2.Close()
两种方式的挑选
fileinfo, _ := os.Stat("aa.txt")
fmt.Println(fileinfo.Mode())
//使用stat获取文件信息 mode获取文件权限信息
//若文件本身可以确定其权限足够,则可直接才有第一种 不够不二中
PS:更多会直接才有第二种方式,因为更加灵活
读取文件对象的内容
//3.使用read方法读取内容
bs := make([]byte, 1, 1024)
n, err3 := file.Read(bs) //n是read方法读取内容的数量 并将内容放入bs切片中
fmt.Println(err3)
fmt.Println(n)
fmt.Println(string(bs)) //bs中的元素是byte类型 需要强制转换一下
read方法需要传入一个byte切片类型读取内容,其N长度就是每次读取文件的内容的长度,
//第一次读取
n, err3 := file.Read(bs)
fmt.Println(err3)
fmt.Println(n)
fmt.Println(string(bs))
//接着第一次读取的位置继续读取
n, err3 := file.Read(bs)
fmt.Println(err3)
fmt.Println(n)
fmt.Println(string(bs))
//当n=0时说明已经将文件内容全部读完,bs中只能打印出最后一次读取的内容 不在被覆盖更新
for 循环读取内容
bs := make([]byte, 1, 1024)
//这里直接使用for循环读取
for {
n, _ := file.Read(bs)
if n == 0 {
return
}
fmt.Print(string(bs))
}
IO写入内容
//这里不加上os.O_append下 每次执行都会把第一行数据清空在写入
file, err := os.OpenFile("aa.txt", os.O_WRONLY|os.O_RDONLY, os.ModePerm)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
br := []byte{65, 66, 67, 68, 69}
n, err2 := file.Write(br)
if err2 != nil {
fmt.Println(err2)
return
}
fmt.Println(n)
//这里添加了apped动作 每次执行都会在全部内容末尾追加写入的内容
file, err := os.OpenFile("aa.txt", os.O_WRONLY|os.O_RDONLY|os.O_APPEND, os.ModePerm)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
br := []byte{65, 66, 67, 68, 69}
n, err2 := file.Write(br)
if err2 != nil {
fmt.Println(err2)
return
}
fmt.Println(n)
字符串直接写入
//可以直接写入字符串
n, err = file.WriteString("nihao,我是中国人")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(n)
不过一般使用 切片读取写入较多
文件复制
func main() {
sour := "./售后联系方式.png"
dest := "d://copy3.png"
//copy(sour, dest, 1024)
//copy2(sour, dest)
copy3(sour, dest)
}
func copy(sour, dest string, bufsize int) {
//获取源文件对象
sourFile, err := os.Open(sour)
if err != nil {
fmt.Println(sourFile)
return
}
defer sourFile.Close()
//获取目标对象且给予权限动作 os.O_CREATE当文件不存在时 会自动创建 不需要加判断 create了
destFile, err2 := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE, os.ModePerm)
if err2 != nil {
fmt.Println(err2)
return
}
defer destFile.Close()
//文件缓冲区
buff := make([]byte, bufsize)
for {
//读取内容
n, err3 := sourFile.Read(buff)
if err3 == io.EOF || n == 0 {
fmt.Println("文件复制完毕")
break
}
//写入内容
_, err3 = destFile.Write(buff[:n])
if err3 != nil {
fmt.Println(err3)
}
}
}
func copy2(sour, dest string) {
sourFile, err := os.Open(sour)
if err != nil {
fmt.Println(sourFile)
return
}
defer sourFile.Close()
//获取目标对象且给予权限动作 os.O_CREATE当文件不存在时 会自动创建 不需要加判断 create了
destFile, err2 := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE, os.ModePerm)
if err2 != nil {
fmt.Println(err2)
return
}
defer destFile.Close()
//调用系统copy方法
wf, _ := io.Copy(destFile, sourFile)
fmt.Println("文件大小:", wf)
}
// 此方法是一次性写入写出 不适用大型文件
func copy3(sour, dest string) {
rfbuff, _ := os.ReadFile(sour)
os.WriteFile(dest, rfbuff, 777)
}
Seeker接口
里面包装了seek方法
type Seeker interface{
Seek(offset int64,whence int)(int64,error)
}
seek(offset,whence)设置指针光标的位置,读写文件
offset:偏移量
whence:从哪里开始计算
0 seekStart 相对于文件开头
1 seekCurrent 相对于当前光标的位置
2 seekend 相对于文件末尾
file, _ := os.OpenFile("./aa.txt", os.O_RDWR, os.ModePerm)
defer file.Close()
//业务
file.Seek(2, io.SeekStart) //偏移量2个从文件开头算起
buf := []byte{0, 8}
file.Read(buf)
fmt.Println(string(buf))
file.Seek(3, io.SeekCurrent) //偏移量3 从上一次光标的位置算起
file.Read(buf)
fmt.Println(string(buf))
file.Seek(0, io.SeekEnd) //偏移量0 从文件末尾开始算
file.WriteString("我肯定在最后")
断点续传
文件过大如何缩短时间
文件传输中断 如何续传
seek方法可以实现
/*
实现断点续传
思路:主要记住上一次已经传递了多少数据,那就可以创建一个临时文件,记录已经传递的数据量,当恢复传递的时候,
先从临时文件读取上次已经传递的数据量,然后通过Seek()方法,设置到该读和写的位置,再继续传输数据
*/
func main() {
//传输源文件
sourFile := "./copy.png"
//传输目的地
destFile := "D:\\new.png"
//临时记录文件
tempFile := "./temp.txt"
//建立文件连接
file1, _ := os.Open(sourFile)
file2, _ := os.OpenFile(destFile, os.O_CREATE|os.O_RDWR, os.ModePerm)
file3, _ := os.OpenFile(tempFile, os.O_CREATE|os.O_RDWR, os.ModePerm)
//关闭连接
defer file1.Close()
defer file2.Close()
//1.读取临时文件中记录的数据
//设置光标的位置
file3.Seek(0, io.SeekStart)
//缓冲区域
buff := make([]byte, 1024, 1024)
//读取file3文件内容
n, _ := file3.Read(buff)
//内容虽然是数字 但是返回的是string类型
countStr := string(buff[:n]) //光标的位置
fmt.Println("countStry:", countStr)
count, _ := strconv.ParseInt(countStr, 10, 64)
//获取到了光标的位置那么源文件与目标文件也要从此开始
file1.Seek(count, io.SeekStart)
file2.Seek(count, io.SeekStart)
bufData := make([]byte, 1024, 1024)
//记录总共记录的多少数据
total := int(count)
for {
redn, err := file1.Read(bufData)
if err == io.EOF {
fmt.Println("文件读取完毕")
//这个时候再关闭临时文件 保险
file3.Close()
os.Remove(tempFile)
break
}
wrin, _ := file2.Write(bufData[:redn])
total += wrin
//将传输的进度记录到临时文件中
file3.Seek(0, io.SeekStart)
file3.WriteString(strconv.Itoa(total))
//if total > 1000026 {
// panic("dd")
//}
}
}
bufio包
这个包可以大幅提高文件读写的效率
增加输入出中的缓冲区 理解同java的inputstreambuff一致
func main() {
file1, _ := os.OpenFile("./aa.txt", os.O_RDWR, os.ModePerm)
defer file1.Close()
//bufio
reder := bufio.NewReader(file1)
buff := make([]byte, 1024)
n, _ := reder.Read(buff)
fmt.Println(n)
fmt.Println(string(buff[:n]))
//读取键盘的输入
ipReader := bufio.NewReader(os.Stdin)
//输入\t也就是回车就结束
str, _ := ipReader.ReadString('\t')
fmt.Println("读取输入:", str)
wri := bufio.NewWriter(file1)
//这里只是写入到了缓冲区 如果达不到缓冲区的值 不会主动写入文件中
wn, _ := wri.WriteString("hello")
//所以这里需要刷新一下缓冲区
fmt.Println("写入:", wn)
wri.Flush()
}
遍历文件夹
func listDir(filepath string) {
dir := filepath
fileinfo, _ := os.ReadDir(dir)
for i, v := range fileinfo {
filename := dir + "\\" + v.Name()
if v.IsDir() {
listDir(filename)
}
fmt.Printf("%d %s", i, filename)
fmt.Println()
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界