Golang09-Go语言I/O操作2ioutil包和bufio包

418 阅读4分钟

ioutil包

ioutil包核心函数如下所示

Sample将abc.txt中的123456789写入xyz.txt中

package main

import (
   "fmt"
   "io/ioutil"
   "os"
)

func main()  {
   fileName1:="./abc.txt"
   //打开文件
   data,err:=ioutil.ReadFile(fileName1)
   if err!=nil{
      fmt.Println("文件打开异常!",err.Error())
   }else{
      fmt.Println(string(data))
   }
   fileName2:="./xyz.txt"
   s1:="JackMa陪你学区块链!"
   //写入文件
   err=ioutil.WriteFile(fileName2,[]byte(s1),0777)
   if err!=nil{
      fmt.Println("写入异常!",err.Error())
   }else{
      fmt.Println("文件写入结束")
   }
   //文件复制
   err=ioutil.WriteFile(fileName2,data,os.ModePerm)
   if err!=nil{
      fmt.Println("文件复制异常!",err.Error())
   }else{
      fmt.Println("文件复制成功!")
   }
   dirName:="./"
   //遍历目录
   file1,err:=ioutil.TempFile(dirName,"temp")
   if err!=nil{
      fmt.Println("创建文件失败!",err.Error())
   }else{
      file1.WriteString("写入内容:"+file1.Name())
   }
   file1.Close()
}
/*
123465789
文件写入结束
文件复制成功!

*/

bufio包

缓冲区原理 bufio实现了缓冲I/O操作,达到高效读写

bufio包对io包下的对象Reader、Writer进行包装,分别实现了io.Reader和io.Writer接口,提供了数据缓冲功能,能够一定程度上减少大块数据读写带来的开销问题,所以bufio比直接读写更快。

缓冲区的设计是为了存储多次的写入,最后一口气把缓冲区内容写入文件。当发起一次读写操作时,计算机会首先尝试从缓冲区获取数据;内容当缓冲区内没有数据时才会从数据源获取数据更新缓冲区。

2.1bufio.Reader结构体

1、bufio.Reader方法

2、NewReader()与NewReaderSize()

将rd封装成一个拥有size大小缓存的bufio.Reader对象,NewReader()相当于NewReaderSize(rd,4096)

3、Read()方法

bufio.Read(p[]byte)相当于读取大小为len(p)的内容,使用思路如下

4、ReadLine()

ReadLine()是一个低级的,原始的行读取操作函数。大多数情况下,应该使用ReadBytes('\n')或者ReadString('\n')或者使用一个Scanner

ReadLine()是通过ReadSlice()方法实现的,返回的是缓存的切片。ReadLine()尝试返回一个单行数据,不包括行尾的"\n"

5、ReadBytes()

6、ReadString() ReadString()功能同ReadBytes(),只不过返回的是一个字符串。

Sample,通过ReadString读取abc.txt文件

package main

import (
   "bufio"
   "fmt"
   "io"
   "os"
)

func testReader()  {
   fileName1:="./abc.txt"
   //打开文件
   file1,_:=os.Open(fileName1)
   //创建缓冲区
   reader1:=bufio.NewReader(file1)
   fmt.Printf("%T\n",reader1)
   for{
      //以\n为分隔符
      s1,err:=reader1.ReadString('\n')
      fmt.Print(s1)
      if err==io.EOF{
         fmt.Println("读取完毕!")
         break
      }
   }
   file1.Close()
}

func main()  {
   testReader()
}

/*
返回
*bufio.Reader
123465789读取完毕!
*/

2.2 bufio.Write结构体

1、bufio.Writer

常用方法

2、Write()

bufio.Write(p [] byte)的使用思路如下

Sample write

这个案例牛逼了,把VivalaVida这首曲子写入了一个空的.mp3文件里面

package main

import (
   "bufio"
   "fmt"
   "io"
   "os"
)

func testWrite()  {
   MP3file:="./vivalavida.MP3"
   //打开文件
   file2,_:=os.Open(MP3file)
   //创建读缓冲区
   reader2:=bufio.NewReader(file2)
   fileName3:="./testmp.mp3"
   //打开文件
   file3,_:=os.OpenFile(fileName3,os.O_WRONLY|os.O_CREATE,os.ModePerm)
   //创建写缓冲区
   write1:=bufio.NewWriter(file3)
   for{
      //将读取到的数据写入另一个文件
      bs,err:=reader2.ReadBytes(' ')
      write1.Write(bs)
      write1.Flush()
      if err== io.EOF{
         fmt.Println("文件读取完毕!")
         break
      }
   }
   file2.Close()
   file3.Close()
}

func main()  {
   testWrite()
}

/*
返回文件读取完毕!打开testmp.mp3,和vivalavida一样
这让我想起之前的解码网抑云音乐会员过期的NCM格式无法被继续进行播放的问题,NCM是一个封装了专辑封面以及Meta的容器格式,里面就包含music data,
*/

网X云音乐ncm编解码探究记录

ncmdump.go - 导出网X云音乐 NCM 格式

2.3Scanner

实际在使用中,更推荐使用Scanner对数据进行读取,而非直接使用Reader类,Scanner可以通过splitFunc将输入数据拆分为多个token,然后依次进行读取。

和Reader类似,Scanner需要绑定io.Reader上。通过NewScanner()进行创建。

函数声明如下所示:

func NewScanner(r io.Readder) *Scanner

可以为Scanner指定splitFunc,方法如下所示:

scanner.split(bufio.ScanWords)

sample,利用Scanner对象指定分割,按照空格进行分割

package main

import (
   "bufio"
   "fmt"
   "strings"
)

func main()  {
   //创建Reader对象并传入要分割的字符串
   reader1:=bufio.NewReader(strings.NewReader("this is a string !"))
   //创建Scanner对象
   scanner:=bufio.NewScanner(reader1)
   //指定分割方法,按照空格进行拆分
   scanner.Split(bufio.ScanWords)
   //循环读取

   for scanner.Scan(){
      fmt.Println(scanner.Text())
      if scanner.Text()=="q!"{
         break
      }
   }
}


/*返回:
this
is
a
string
!
*/

I/O操作小结: 这部分还是有点难,难点在于需要记的东西比较多。主要讲的就是如何打开文件,关闭文件、读写操作、缓冲区的作用?对文件进行读写,缓冲区不仅仅用在文件读写,在网络通信中也起到了很大的作用。这章节有时间下来多实践,多写代码。