Go 第17章 文件操作 Go 第17章 文件操作

2023-09-25

一、io 包基础接口

type Reader interface {
   Read(p []byte)(n int,err error)
}

将 len(p) 个字节读取到 p 中

ReadFrom() 常用方法,实现了 Reader 接口的都可以用

type Writer interface {
   Write(p []byte)(n int,err error)
}

Write 方法用于将 p 中的数据写入到对象中的数据流中

type Seeker interface {
   Seek(offset int64, whence int)(ret int64, err error)
}
  • Seek 设置下一次读写操作的指针位置,每次的读写操作都是从指针位置开始的

  • whence 为 0:表示从数据的开头开始移动指针

  • whence 为 1:表示从数据的当前指针位置开始移动指针

  • whence 为 2:表示从数据的尾部开始移动指针

  • SeekStart = 0 //seek relative to the origin of the file

  • SeekCurrent = 1 //seek relative to the current offset

  • SeekEnd =2 //seek relative to the end

  • offset 是指针移动的偏移量

type Closer interface {
   Close() error
}
  • Close 一般用于关闭文件,关闭连接,关闭数据库等

一些常量

  • O_RDONLY int = syscall.O_RDONLY //只读模式打开文件

  • O_WRONLY int = syscall.O_WRONLY //只写模式打开文件

  • O_RDWR int = syscal.O_RDWR //读写模式开文件

  • O_APPEND int = syscall.O_APPEND //写操作时将数据附加到文件尾部

  • O_CREATE int = syscall.O_CREAT //如果不存在将创建一个新文件

  • O_EXCL int = syscall.O_EXCL //和O_CREATE配合使用,文件必须不存在

  • O_SYNC int = syscall.O_SYNC //打开文件用于同步 I/O

  • O_TRUNC int = syscall.O_TRUNC //如果可能,打开时清空文件

写文件实例:

package main

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

func main() {
   f, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_RDWR, 0777)
   if err != nil {
      fmt.Println(err)
      return
   }
   _, err = f.Seek(0, io.SeekEnd)
   if err != nil {
      return
   }
   _, err = f.Write([]byte("我是如来佛祖玉皇大帝观音菩萨指定取西经特派使者花果山水帘洞美猴王齐天大圣孙悟空啊!帅到掉渣!"))
   if err != nil {
      return
   }
}

读文件实例:

package main

import (
   "fmt"
   "os"
)

func main() {
   f, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_RDWR, 0777)
   if err != nil {
      fmt.Println(err)
      return
   }
   for {
      b := make([]byte, 12)
      n, err := f.Read(b)
      if err != nil {
         fmt.Println(err)
         return
      }
      fmt.Println(string(b), n)
   }
}

二、读取文件的几个关键方法

  • os.openFile() 用于打开文件,获取到 *fire

  • bufio.newReader(f) 将文件变化为 reader

  • reader.ReadString('字符') 调用 reader 上的方法还有 ReadLine ReadByte Readslice 等

  • ioutil.ReadAll(f) 直接读取整个文件 os.ReadFile(文件路径) 也能达到同样效果

  • os.ReadDir("./") 读取文件夹,获取目标文件夹下的文件信息

修改 test.txt

我是如来佛祖
玉皇大帝
观音菩萨
指定取西经
特派使者
花果山
水帘洞
美猴王
齐天大圣
孙悟空啊!
帅到掉渣!

bufio.NewReader.ReadString

package main

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

func main() {
   f, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_RDWR, 0777)
   if err != nil {
      fmt.Println(err)
      return
   }
   reader := bufio.NewReader(f)
   for {
      str, err := reader.ReadString('\n')
      if err != nil {
         fmt.Println(err.Error())
         return
      }
      fmt.Println(str)
   }
}

bufio.NewReader.ReadLine

package main

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

func main() {
   f, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_RDWR, 0777)
   if err != nil {
      fmt.Println(err)
      return
   }
   reader := bufio.NewReader(f)
   for {
      str, isPrefix, err := reader.ReadLine()
      if err != nil {
         fmt.Println(err.Error(), isPrefix)
         return
      }
      fmt.Println(string(str), isPrefix)
   }
}

ioutil.ReadAll:已被弃用

package main

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

func main() {
   f, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_RDWR, 0777)
   if err != nil {
      fmt.Println(err)
      return
   }
   b, _ := ioutil.ReadAll(f)
   fmt.Println(string(b))
}

os.ReadFile

package main

import (
   "fmt"
   "os"
)

func main() {
   b, _ := os.ReadFile("./test.txt")
   fmt.Println(string(b))
}

os.ReadDir

package main

import (
   "fmt"
   "os"
)

func main() {
   d, err := os.ReadDir("./")
   fmt.Println(err)
   for _, v := range d {
      fmt.Println(v.Info())
      fmt.Println(v.Name())
      fmt.Println(v.IsDir())
      fmt.Println(v.Type())
   }
}

三、写文件的几个关键方法

  • os.openFile() 用于打开文件 获取到 *fire

  • f.seek() 挪光标位置

  • friteString() 直接写入

  • bufio.NewWriter(f) 创建一个缓存的写

    • writer.Writestring() 先写入内存

    • writer.Flush() 缓存内容生效 写入文件

package main

import (
   "bufio"
   "fmt"
   "os"
   "strconv"
)

func main() {
   f, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_RDWR, 0777)
   if err != nil {
      fmt.Println(err)
      return
   }
   writer := bufio.NewWriter(f)
   reader := bufio.NewReader(f)
   n := 0
   for {
      n++
      str, err := reader.ReadString('\n')
      writer.WriteString(strconv.Itoa(n) + " " + str)
      if err != nil {
         fmt.Println(err)
         break
      }
   }
   _, err = f.Seek(0, 0)
   if err != nil {
      return
   }
   err = writer.Flush()
   if err != nil {
      return
   }
}

打开 test.txt,发现文件内容变化了

1 我是如来佛祖
2 玉皇大帝
3 观音菩萨
4 指定取西经
5 特派使者
6 花果山
7 水帘洞
8 美猴王
9 齐天大圣
10 孙悟空啊!
11 帅到掉渣!

复制文件:open 两个文件然后 io.Copy(dst, src)

package main

import (
   "io"
   "os"
)

func main() {
   f1, _ := os.OpenFile("./test.txt", os.O_CREATE|os.O_RDWR, 0777)
   f2, _ := os.OpenFile("./testCopy.txt", os.O_CREATE|os.O_RDWR, 0777)
   _, err := io.Copy(f2, f1)
   if err != nil {
      return
   }
}

注意:io.Copy 只是把 test.txt 中的文件内容覆盖到 testCopy.txt 中而已,如果 testCopy.txt 的文件行数比 test.txt 长,则 testCopy.txt 后面的内容依然存在,比如我们修改 testCopy.txt 为

1 我是如来佛祖
2 玉皇大帝
3 观音菩萨
4 指定取西经
5 特派使者
6 花果山
7 水帘洞
8 美猴王
9 齐天大圣
10 孙悟空啊!
11 帅到掉渣!
12 帅到掉渣!

再次执行代码,则 testCopy.txt 的文件内容依然不变

阅读 338