文件是什么

计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件(以ASCII码存储的文件)和二进制文件(包含其他数据的文件),文本文件后缀通常是.txt,二进制文件有.bat,.bin,.exe等等

io和Reader及Writer接口

.什么是io,在计算机中指的是input/output,由于程序运行时数据是在内存中驻留的,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘,网络等。就需要IO接口

在Go中,输入输出操作是通过能读能写的字节流数据模型来实现的,为此,io包提供了io.Reader和io.Writer来进行输入输出操作,如下图

Go的文件操作小结_缓存

 

 

我们看到的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()   //将缓存中的字符串写到文件中
 }