onlyxue

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  31 随笔 :: 0 文章 :: 0 评论 :: 2399 阅读

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()

   }

}
posted on   守望在路上  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界
点击右上角即可分享
微信分享提示