一文详解Go文件操作的多种姿势

504 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 24天,点击查看活动详情

文件资源

os.Open()函数能够打开一个文件,返回一个*File和一个err。对得到的文件实例调用close()方法能够关闭文件

func main() {
  file, err := os.Open("./07_package/07_file_test.txt") //路径以项目根目录为开始
  //file, err := os.OpenFile("./07_package/07_file_test.txt", os.O_RDONLY, 0)
  if err != nil {
    fmt.Println("file open err:", err)
    return
  }
  defer file.Close()
  fmt.Println(file)
}

注意点:文件路径,是以项目根目录为开始

os.OpenFile()的使用:

func OpenFile(name string, flag int, perm FileMode) (*File, error) {}

其中:

  • name:要打开的文件名

  • flag:打开文件的模式。 模式有以下几种:

    • os.O_WRONLY 只写
    • os.O_CREATE 创建文件
    • os.O_RDONLY 只读
    • os.O_RDWR 读写
    • os.O_TRUNC 清空
    • os.O_APPEND 追加
  • perm:文件权限,一个八进制数。r(读)04,w(写)02,x(执行)01

文件读写

方式1:os包读写

基本读取

func main() {
  file, err := os.Open("./07_package/07_file_test.txt")
  if err != nil {
    fmt.Println("file open err:", err)
    return
  }
  defer file.Close()

  tmp := make([]byte, 128) //注意:这里只能读取到128个字节数据
  n, err := file.Read(tmp)
  if err != nil && err != io.EOF { //io.EOF代表读取到空文件或文件结尾,这个错误得排除掉
    fmt.Println("file read err:", err)
    return
  }
  fmt.Printf("读取的文件有%d字节数据\n", n)
  fmt.Printf("读取的内容:%s\n", string(tmp[:n]))
}

上面的用法,有读取数据长度的局限性,所以得用下面的方法,循环去读取

循环读取

func main() {
  file, err := os.Open("./07_package/07_file_test.txt")
  if err != nil {
    fmt.Println("file open err:", err)
    return
  }
  defer file.Close()

  //循环读取(要用io.EOF终止循环)
  content := make([]byte, 0)
  for {
    tmp := make([]byte, 128)
    n, err := file.Read(tmp)
    if err == io.EOF {
      fmt.Println("文件已读取完成")
      break
    }
    if err != nil {
      fmt.Println("file read err:", err)
      return
    }
    content = append(content, tmp[:n]...)
  }
  fmt.Printf("读取的文件有%d字节数据\n", len(content))
  fmt.Printf("读取的内容:%s\n", string(content))
}

写入数据

func main() {
  file, err := os.OpenFile("./07_package/07_file_test.txt", os.O_WRONLY|os.O_APPEND, 0666)
  if err != nil {
    fmt.Println("file open err:", err)
    return
  }
  defer file.Close()

  str := "\nosWrite " + strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
  file.Write([]byte(str))
  n, _ := file.WriteString(str)
  fmt.Printf("写入文件字节数:%d\n", n)
}

方式2:bufio包读写

读取

逐行读取文件数据,注意io.EOF读到尾部时,需要特殊处理下尾部的数据

func main() {
  file, err := os.Open("./07_package/07_file_test.txt")
  if err != nil {
    fmt.Println("file open err:", err)
    return
  }
  defer file.Close()

  reader := bufio.NewReader(file)
  //循环读取(指定按行定界符,使用io.EOF终止)
  content := ""
  for {
    line, err := reader.ReadString('\n')
    if err == io.EOF {
      if len(line) != 0 { //注意:这里是为了能读取到最后一行的数据
        fmt.Printf(line)
        content += line
      }
      fmt.Println("文件已读取完成")
      break
    }
    if err != nil {
      fmt.Println("reader.ReadString err:", err)
      return
    }
    fmt.Printf(line)
    content += line
  }
  fmt.Println("读取的内容:", content)
}

写入

func main() {
  file, err := os.OpenFile("./07_package/07_file_test.txt", os.O_WRONLY|os.O_APPEND, 0666)
  if err != nil {
    fmt.Println("file open err:", err)
    return
  }
  defer file.Close()

  writer := bufio.NewWriter(file)
  str := "\nbufioWrite " + strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
  n, _ := writer.WriteString(str) //将数据先写入缓存
  writer.Flush()                  //将缓存中的内容写入文件

  fmt.Printf("写入文件字节数:%d\n", n)
}

方式3:io/ioutil包读写

读取

能够读取完整的文件,只需要将文件名作为参数传入

func main() {
  content, err := ioutil.ReadFile("./07_package/07_file_test.txt")
  if err != nil {
    fmt.Println("ioutil.ReadFile err:", err)
    return
  }
  fmt.Println(string(content))
}

写入

会直接全量覆盖,不能指定按追加的方式写入。解决方法:写读取数据,拼接后再写入

func main() {
  str := "\nioutilWrite " + strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
  err := ioutil.WriteFile("./07_package/07_file_test.txt", []byte(str), 0666)
  if err != nil {
    fmt.Println("ioutil.WriteFile err:", err)
    return
  }
  fmt.Println("ioutil.WriteFile success")
}

如果本文对你有帮助,欢迎点赞收藏加关注,如果本文有错误的地方,欢迎指出!