Go语言文件操作

Posted show58

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言文件操作相关的知识,希望对你有一定的参考价值。

获取文件信息

os.Stat()函数,返回fileInfo和err信息。

func main() {
    fileInfo, err := os.Stat("xx/test.txt")
    if err != nil {
        fmt.Println("get info err", err)
        return //将函数返回
    }
    //获取文件名
    fmt.Println(fileInfo.Name()) //test.txt
    //获取文件大小
    fmt.Println(fileInfo.Size()) //540
    //是否为目录
    fmt.Println(fileInfo.IsDir()) //false
    //修改时间
    fmt.Println(fileInfo.ModTime()) //2019-08-28 11:28:33.405318773 +0800 CST
    //权限
    fmt.Println(fileInfo.Mode()) //-rw-r--r--
}

打开和关闭文件

os.Open()函数能够打开一个文件,返回一个*File和一个err,通过此种方式打开文件是只读的。
file.close()方法能够关闭文件。

//打开和关闭文件
func main()  {
    file,err := os.Open("test.txt")
    if err != nil{
        fmt.Println("打开文件失败",err)
        return
    }
    //文件能打开的情况下,使用defer延迟关闭文件
    defer file.Close()
}

读取文件

基本使用

file.Read()方法可以读取文件,它接收一个字节切片,返回读取的字节数和可能的具体错误,读到文件末尾时会返回0和io.EOF。
定义:

func (f *File) Read(b []byte) (n int, err error)

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

示例:

func main() {
    //打开文件
    f,err := os.Open("woceng.txt")
    if err!= nil{
        fmt.Println("文件打开失败",err)
        return
    }
    //关闭文件
    defer f.Close()
    //读取文件
    var geci = make([]byte,256)
    g,err := f.Read(geci)
    if err == io.EOF{
        fmt.Println("文件读取完毕!")
        return
    }
    if err!= nil{
        fmt.Println("文件打开失败",err)
        return
    }
    //只会读取之前切片定义的256字节数据,若文件内容大于256字节,则超出部分无法显示
    fmt.Printf("读取了%d字节数据
", g)
    fmt.Println(string(geci[:g])) //将byte转换成string
}

循环读取

使用for循环读取。

var geci = make([]byte,256)
    for {
        g,err := f.Read(geci)
        if err == io.EOF{
            fmt.Println("文件读取完毕!")
            return
        }
        if err!= nil{
            fmt.Println("文件打开失败",err)
            return
        }
        //会全部读取,但是每256字节会进行重新读取,可能会出现乱码
        fmt.Printf("读取了%d字节数据
", g)
        fmt.Println(string(geci[:g]))
    }

bufio读取文件

读取文件中会有个缓冲区,先把内容读到缓冲区,然后统一读取,不过可能会丢数据(内存)。

func main()  {
    file,err := os.Open("woceng.txt")
    if err != nil{
        fmt.Println("文件读取错误",err)
        return
    }
    defer file.Close()
    // 利用缓冲区从文件读数据
    reader := bufio.NewReader(file)
    for{
        line,err := reader.ReadString(‘
‘) //字符串读取,每到换行就停止
        if err == io.EOF {
            fmt.Println("文件读完了")
            break
        }
        if err != nil {
            fmt.Println("read file failed, err:", err)
            return
        }
        fmt.Print(line)
    }
}

ioutil读取整个文件

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

// ioutil读取文件
func readioutil(filename string)  {
    content,err := ioutil.ReadFile(filename)
    if err != nil{
        fmt.Println("文件读取错误",err)
        return
    }
    fmt.Println(string(content))
}

文件写入

os.OpenFile()方法实现文件写入相关功能。
语法:

func OpenFile(name string, flag int, perm FileMode) (*File, error) {
    ...
}
type Writer interface {
    Write(p []byte) (n int, err error)
}

name:要打开的文件名
flag:打开文件的模式
perm:文件权限,一个八进制数

模式含义
os.O_WRONLY 只写
os.O_CREATE 创建文件
os.O_RDONLY 只读
os.O_RDWR 读写
os.O_TRUNC 清空
os.O_APPEND 追加

Write和WriteString

//打开文件支持文件写入
func main()  {
    file,err := os.OpenFile("test.txt",os.O_CREATE|os.O_APPEND|os.O_WRONLY,0644)
    if err != nil{
        fmt.Println("打开文件失败",err)
        return
    }
    defer file.Close()
    str := "ares"
    file.Write([]byte("666
")) //写入字节切片数据
    file.WriteString(str)       //直接写入字符串数据
}

bufio.NewWriter

将数据先写入缓存。

//打开文件支持文件写入
func main()  {
    file,err := os.OpenFile("test.txt",os.O_CREATE|os.O_APPEND|os.O_WRONLY,0644)
    if err != nil{
        fmt.Println("打开文件失败",err)
        return
    }
    defer file.Close()
    writer := bufio.NewWriter(file)
    for i := 0;i<10;i++{
        writer.WriteString("heoolo
")  ////将数据先写入缓存
    }
    writer.Flush()  //将缓存中的内容写入文件
}

ioutil.WriteFile

将内容直接写入文件中,避免了打开文件操作。直接覆盖文件内容

func main()  {
    str := "aresares"
    err := ioutil.WriteFile("test.txt",[]byte(str),0644)
    if err != nil{
        fmt.Println("写文件失败",err)
        return
    }
}

ioutil.ReadDir实现文件目录遍历

func listFiles(dirname string, level int) {
    // level用来记录当前递归的层次
    s := "--" //生成空格
    for i := 0; i < level; i++ {
        s = "| " + s
    }
    fileInfos, err := ioutil.ReadDir(dirname)
    if err != nil {
        fmt.Println("err:", err)
    }
    for _, fi := range fileInfos {
        filename := dirname + "/" + fi.Name()
        fmt.Printf("%s%s
", s, filename)
        if fi.IsDir() {
            listFiles(filename, level+1)
        }
    }

}
func main() {
    //目录遍历
    dirname := "/Users/wangxin/Documents"
    listFiles(dirname, 0)
}

文件复制

package main

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

func main() {
    srcFile := "xx/src.txt"
    destFile := "xx/dest1.txt"
    total, err := CopyFile(srcFile, destFile)
    fmt.Println(total, err)
    total1, err := CopyFile1(srcFile, destFile)
    fmt.Println(total1, err)
    total2, err := CopyFile3(srcFile, destFile)
    fmt.Println(total2, err)
}

//使用io.Copy()方法实现拷贝,返回拷贝的总数量,错误
func CopyFile(srcFile, destFile string) (int64, error) {
    file1, err := os.Open(srcFile)
    if err != nil {
        return 0, err
    }
    file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
    if err != nil {
        return 0, err
    }
    defer file1.Close()
    defer file2.Close()
    return io.Copy(file2, file1)
}

//通过io操作实现文件拷贝,返回拷贝的总数量及错误
func CopyFile1(srcFile, destFile string) (int, error) {
    file1, err := os.Open(srcFile)
    if err != nil {
        return 0, err
    }
    file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
    if err != nil {
        return 0, err
    }
    defer file1.Close()
    defer file2.Close()
    //读写
    str := make([]byte, 100, 100) //拷贝的时间与此处定义的大小有关
    n := -1                       //读取的数据量
    total := 0
    for {
        n, err = file1.Read(str)
        if err == io.EOF || n == 0 {
            fmt.Println("拷贝结束!")
            break
        } else if err != nil {
            fmt.Println("copy err", err)
            return total, err
        }
        total += n
        file2.Write([]byte("
"))
        file2.Write(str[:n])
    }
    return total, nil
}

//通过ioutil操作实现文件拷贝,返回拷贝的总数量及错误,不适用大文件
func CopyFile3(srcFile, destFile string) (int, error) {
    str, err := ioutil.ReadFile(srcFile)
    if err != nil {
        return 0, err
    }
    err = ioutil.WriteFile(destFile, str, 0644)
    if err != nil {
        return 0, err
    }
    return len(str), nil
}

断点续传

Seeker接口

type Seeker interface {
        Seek(offset int64, whence int) (int64, error)
}

offset:设置偏移量
whence:

  • 0:seekStart表示相对于文件开始,
  • 1:seekCurrent表示相对于当前偏移量,
  • 2:seek end表示相对于结束。
func main() {
    file, _ := os.OpenFile("xx/file01/src.txt", os.O_RDWR, 0644)
    defer file.Close()
    //创建一个切片
    str := []byte{0}
    file.Read(str)
    fmt.Println(string(str))   //A
    file.Seek(2, io.SeekStart) //相对文件开始从下标为2的位置开始读取文件
    file.Read(str)
    fmt.Println(string(str))     //C
    file.Seek(3, io.SeekCurrent) //相对于当前位置(下标为2)往后3个偏移量位置读取文件
    file.Read(str)
    fmt.Println(string(str)) //G
    file.Seek(2, io.SeekEnd) //相对于文件末尾,写入文件
    file.WriteString("QWE") //会在文件末尾写入QWE
}

断点续传实现

创建一个临时文件,记录已经传递的数据量,当恢复传递的时候,先从临时文件中读取上次已经传递的数据量,然后通过Seek()方法,设置到该读和该写的位置,再继续传递数据。

//定义一个错误处理函数
func HandleErr(err error) {
    if err != nil {
        fmt.Println(err)
    }
}
func main() {
    srcFile := "xx/src.txt"
    destFile := "xx/src1.txt"
    //destFile := srcFile[strings.LastIndex(srcFile, "/")+1:] + "dest.txt" //获取源文件名
    tempFile := destFile + "tmp.txt" //临时文件
    //fmt.Println(srcFile)
    //fmt.Println(destFile)
    //fmt.Println(tempFile)
    file1, err := os.Open(srcFile)
    HandleErr(err)
    file2, err := os.OpenFile(destFile, os.O_CREATE|os.O_WRONLY, 0644)
    HandleErr(err)
    file3, err := os.OpenFile(tempFile, os.O_CREATE|os.O_RDWR, 0644)
    HandleErr(err)
    defer file1.Close()
    defer file2.Close()
    //读取临时文件中的数据
    file3.Seek(0, io.SeekStart)
    //创建切片存储临时文件数据
    bs := make([]byte, 100, 100)
    n1, err := file3.Read(bs)
    HandleErr(err)
    fmt.Println(n1)
    countStr := string(bs[:n1])                     //获取临时文件的数据
    couunt, _ := strconv.ParseInt(countStr, 10, 64) //将数据转为10进制64位数据
    fmt.Println(couunt)
    //设置读写的偏移量
    file1.Seek(couunt, io.SeekStart)
    file2.Seek(couunt, io.SeekStart)
    data := make([]byte, 1024, 1024)
    n2 := -1             //读的数据量
    n3 := -1             //写的数据量
    total := int(couunt) //读取总量
    //读取数据
    for {
        n2, err = file1.Read(data)
        if err == io.EOF || n2 == 0 {
            fmt.Println("复制完毕、、")
            file3.Close()
            //删除临时文件
            os.Remove(tempFile)
            break
        }
        //将数据写入目标文件
        n3, _ = file2.Write(data[:n2])
        total += n3
        //将复制总量,存储到临时文件中
        file3.Seek(0, io.SeekStart)
        file3.WriteString(strconv.Itoa(total))
    }
}

以上是关于Go语言文件操作的主要内容,如果未能解决你的问题,请参考以下文章

go语言-关于文件的操作和解释

超赞的 Go 语言 INI 文件操作

[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础

Day05 Go语言文件操作,结构体,构造函数,方法接收器,json序列化

go 语言的一个赋值操作

Go语言文件操作