前言

asongUnixGo

Go语言版本:1.18

操作文件包括哪些

操作一个文件离不开这几个动作:

  • 创建文件
  • 打开文件
  • 读取文件
  • 写入文件
  • 关闭文件
  • 打包/解包
  • 压缩/解压缩
  • 改变文件权限
  • 删除文件
  • 移动文件
  • 重命名文件
  • 清空文件

所以本文就针对这些操作总结了一些示例方法供大家参考;

Go语言操作文件可使用的库

osio/ioutilbufio
osIObufioio/ioutilIOGo1.16io/ioutilio/ioutilio

文件的基础操作

osIO
import (
 "log"
 "os"
)
func main() {
 // 创建文件
 f, err := os.Create("asong.txt")
 if err != nil{
  log.Fatalf("create file failed err=%s\n", err)
 }
 // 获取文件信息
 fileInfo, err := f.Stat()
 if err != nil{
  log.Fatalf("get file info failed err=%s\n", err)
 }

 log.Printf("File Name is %s\n", fileInfo.Name())
 log.Printf("File Permissions is %s\n", fileInfo.Mode())
 log.Printf("File ModTime is %s\n", fileInfo.ModTime())

 // 改变文件权限
 err = f.Chmod(0777)
 if err != nil{
  log.Fatalf("chmod file failed err=%s\n", err)
 }

 // 改变拥有者
 err = f.Chown(os.Getuid(), os.Getgid())
 if err != nil{
  log.Fatalf("chown file failed err=%s\n", err)
 }

 // 再次获取文件信息 验证改变是否正确
 fileInfo, err = f.Stat()
 if err != nil{
  log.Fatalf("get file info second failed err=%s\n", err)
 }
 log.Printf("File change Permissions is %s\n", fileInfo.Mode())

 // 关闭文件
 err = f.Close()
 if err != nil{
  log.Fatalf("close file failed err=%s\n", err)
 }
 
 // 删除文件
 err = os.Remove("asong.txt")
 if err != nil{
  log.Fatalf("remove file failed err=%s\n", err)
 }
}

写文件

快写文件

osioutilWriteFile
func writeAll(filename string) error {
 err := os.WriteFile("asong.txt", []byte("Hi asong\n"), 0666)
 if err != nil {
  return err
 }
 return nil
}

按行写文件

osbuffoos.WriteStringbufio.WriteString
import (
 "bufio"
 "log"
 "os"
)
// 直接操作IO
func writeLine(filename string) error {
 data := []string{
  "asong",
  "test",
  "123",
 }
 f, err := os.OpenFile(filename, os.O_WRONLY, 0666)
 if err != nil{
  return err
 }

 for _, line := range data{
  _,err := f.WriteString(line + "\n")
  if err != nil{
   return err
  }
 }
 f.Close()
 return nil
}
// 使用缓存区写入
func writeLine2(filename string) error {
 file, err := os.OpenFile(filename, os.O_WRONLY, 0666)
 if err != nil {
  return err
 }

 // 为这个文件创建buffered writer
 bufferedWriter := bufio.NewWriter(file)
 
 for i:=0; i < 2; i++{
  // 写字符串到buffer
  bytesWritten, err := bufferedWriter.WriteString(
   "asong真帅\n",
  )
  if err != nil {
   return err
  }
  log.Printf("Bytes written: %d\n", bytesWritten)
 }
 // 写内存buffer到硬盘
 err = bufferedWriter.Flush()
 if err != nil{
  return err
 }

 file.Close()
 return nil
}

偏移量写入

oswriteAt
import "os"

func writeAt(filename string) error {
 data := []byte{
  0x41, // A
  0x73, // s
  0x20, // space
  0x20, // space
  0x67, // g
 }
 f, err := os.OpenFile(filename, os.O_WRONLY, 0666)
 if err != nil{
  return err
 }
 _, err = f.Write(data)
 if err != nil{
  return err
 }

 replaceSplace := []byte{
  0x6F, // o
  0x6E, // n
 }
 _, err = f.WriteAt(replaceSplace, 2)
 if err != nil{
  return err
 }
 f.Close()
 return nil
}

缓存区写入

osIOIOCPUIObufio
import (
 "bufio"
 "log"
 "os"
)

func writeBuffer(filename string) error {
 file, err := os.OpenFile(filename, os.O_WRONLY, 0666)
 if err != nil {
  return err
 }

 // 为这个文件创建buffered writer
 bufferedWriter := bufio.NewWriter(file)

 // 写字符串到buffer
 bytesWritten, err := bufferedWriter.WriteString(
  "asong真帅\n",
 )
 if err != nil {
  return err
 }
 log.Printf("Bytes written: %d\n", bytesWritten)

 // 检查缓存中的字节数
 unflushedBufferSize := bufferedWriter.Buffered()
 log.Printf("Bytes buffered: %d\n", unflushedBufferSize)

 // 还有多少字节可用(未使用的缓存大小)
 bytesAvailable := bufferedWriter.Available()
 if err != nil {
  return err
 }
 log.Printf("Available buffer: %d\n", bytesAvailable)
 // 写内存buffer到硬盘
 err = bufferedWriter.Flush()
 if err != nil{
  return err
 }

 file.Close()
 return nil
}

读文件

读取全文件

有两种方式我们可以读取全文件:

osio/ioutilreadFileio/ioutilReadAll
import (
 "io/ioutil"
 "log"
 "os"
)

func readAll(filename string) error {
 data, err := os.ReadFile(filename)
 if err != nil {
  return err
 }
 log.Printf("read %s content is %s", filename, data)
 return nil
}

func ReadAll2(filename string) error {
 file, err := os.Open("asong.txt")
 if err != nil {
  return err
 }

 content, err := ioutil.ReadAll(file)
 log.Printf("read %s content is %s\n", filename, content)

 file.Close()
 return nil
}

逐行读取

osReadbufiobufioReadLineReadBytes("\n")ReadString("\n")ReadBytes("\n")
func readLine(filename string) error {
 file, err := os.OpenFile(filename, os.O_RDONLY, 0666)
 if err != nil {
  return err
 }
 bufferedReader := bufio.NewReader(file)
 for {
  // ReadLine is a low-level line-reading primitive. Most callers should use
  // ReadBytes('\n') or ReadString('\n') instead or use a Scanner.
  lineBytes, err := bufferedReader.ReadBytes('\n')
  bufferedReader.ReadLine()
  line := strings.TrimSpace(string(lineBytes))
  if err != nil && err != io.EOF {
   return err
  }
  if err == io.EOF {
   break
  }
  log.Printf("readline %s every line data is %s\n", filename, line)
 }
 file.Close()
 return nil
}

按块读取文件

有些场景我们想按照字节长度读取文件,这时我们可以如下方法:

osReadosbufio.NewReaderReadosioReadFullReadAtLeast
// use bufio.NewReader
func readByte(filename string) error {
 file, err := os.OpenFile(filename, os.O_RDONLY, 0666)
 if err != nil {
  return err
 }
 // 创建 Reader
 r := bufio.NewReader(file)

 // 每次读取 2 个字节
 buf := make([]byte, 2)
 for {
  n, err := r.Read(buf)
  if err != nil && err != io.EOF {
   return err
  }

  if n == 0 {
   break
  }
  log.Printf("writeByte %s every read 2 byte is %s\n", filename, string(buf[:n]))
 }
 file.Close()
 return nil
}

// use os
func readByte2(filename string) error{
 file, err := os.OpenFile(filename, os.O_RDONLY, 0666)
 if err != nil {
  return err
 }

 // 每次读取 2 个字节
 buf := make([]byte, 2)
 for {
  n, err := file.Read(buf)
  if err != nil && err != io.EOF {
   return err
  }

  if n == 0 {
   break
  }
  log.Printf("writeByte %s every read 2 byte is %s\n", filename, string(buf[:n]))
 }
 file.Close()
 return nil
}


// use os and io.ReadAtLeast
func readByte3(filename string) error{
 file, err := os.OpenFile(filename, os.O_RDONLY, 0666)
 if err != nil {
  return err
 }

 // 每次读取 2 个字节
 buf := make([]byte, 2)
 for {
  n, err := io.ReadAtLeast(file, buf, 0)
  if err != nil && err != io.EOF {
   return err
  }

  if n == 0 {
   break
  }
  log.Printf("writeByte %s every read 2 byte is %s\n", filename, string(buf[:n]))
 }
 file.Close()
 return nil
}

分隔符读取

bufioScannerSplitSplitScanLinesbufioScanRunesScanWrodsSacnWrods
func readScanner(filename string) error {
 file, err := os.OpenFile(filename, os.O_RDONLY, 0666)
 if err != nil {
  return err
 }

 scanner := bufio.NewScanner(file)
 // 可以定制Split函数做分隔函数
 // ScanWords 是scanner自带的分隔函数用来找空格分隔的文本字
 scanner.Split(bufio.ScanWords)
 for {
  success := scanner.Scan()
  if success == false {
   // 出现错误或者EOF是返回Error
   err = scanner.Err()
   if err == nil {
    log.Println("Scan completed and reached EOF")
    break
   } else {
    return err
   }
  }
  // 得到数据,Bytes() 或者 Text()
  log.Printf("readScanner get data is %s", scanner.Text())
 }
 file.Close()
 return nil
}

打包/解包

archivetarzipzip
zip
import (
 "archive/zip"
 "fmt"
 "io"
 "log"
 "os"
)

func main()  {
 // Open a zip archive for reading.
 r, err := zip.OpenReader("asong.zip")
 if err != nil {
  log.Fatal(err)
 }
 defer r.Close()
 // Iterate through the files in the archive,
 // printing some of their contents.
 for _, f := range r.File {
  fmt.Printf("Contents of %s:\n", f.Name)
  rc, err := f.Open()
  if err != nil {
   log.Fatal(err)
  }
  _, err = io.CopyN(os.Stdout, rc, 68)
  if err != nil {
   log.Fatal(err)
  }
  rc.Close()
 }
}
zip
func writerZip()  {
 // Create archive
 zipPath := "out.zip"
 zipFile, err := os.Create(zipPath)
 if err != nil {
  log.Fatal(err)
 }

 // Create a new zip archive.
 w := zip.NewWriter(zipFile)
 // Add some files to the archive.
 var files = []struct {
  Name, Body string
 }{
  {"asong.txt", "This archive contains some text files."},
  {"todo.txt", "Get animal handling licence.\nWrite more examples."},
 }
 for _, file := range files {
  f, err := w.Create(file.Name)
  if err != nil {
   log.Fatal(err)
  }
  _, err = f.Write([]byte(file.Body))
  if err != nil {
   log.Fatal(err)
  }
 }
 // Make sure to check the error on Close.
 err = w.Close()
 if err != nil {
  log.Fatal(err)
 }
}

总结

osiobufioGo

好啦,本文到这里就结束了,我是asong,我们下期见。

欢迎关注公众号:Golang梦工厂