zoukankan      html  css  js  c++  java
  • Go中的文件读写

    在 Go 语言中,文件使用指向 os.File 类型的指针来表示的,也叫做文件句柄 。我们来看一下os包的使用方式。

    1.读取文件

    os包提供了两种打开文件的方法:

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

    第一个方法是以只读的方式去打开文件,如果文件不存在或者程序没有足够的权限打开这个文件,Open函数会返回错误;

    第二个方法会自由一些,你可以设置打开文件的方式,以及文件的操作权限,后面我们详细说明。

    package main
    
    import (
        "fmt"
        "os"
    )
    func main() {
        file, e := os.Open("c:/1.txt")
        if e != nil {
            fmt.Println(e)
        }
        buf := make([]byte,1024)
        for {
            len, _ := file.Read(buf)
            if len == 0 {
                break
            }
            fmt.Println(string(buf))
        }
    
        buf1 := make([]byte,1024)
        offset := 0
        for {
            len1, _ := file.ReadAt(buf1, int64(offset))
            offset = offset + len1
            if len1 == 0 {
                break
            }
            fmt.Println(string(buf1))
        }
        file.Close()
    }
    

    这是一个简单的打开文件读取数据的例子。

    file.Read()方法是直接将文件内容读取到指定大小的byte数组中,由源码可知如果byte数组大于1G,那么默认一次最大可以读取1G大小的数据。

    file.ReadAt()方法可以手动指定每次读取位置的偏移量。而不是默认设置。

    我们再看OpenFile方法:

    package main
    
    import (
        "fmt"
        "os"
    )
    func main() {
        //以读写方式打开文件,如果不存在,则创建
        openFile, e := os.OpenFile("c:/1.txt", os.O_RDWR|os.O_CREATE, 777)
        if e != nil {
            fmt.Println(e)
        }
        buf := make([]byte,1024)
        for {
            len, _ := openFile.Read(buf)
            if len == 0 {
                break
            }
            fmt.Println(string(buf))
        }
        openFile.Close()
    }
    

    OpenFile函数的第二个参数是文件的打开模式:

    const (
    	// Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
    	O_RDONLY int = syscall.O_RDONLY // 只读模式
    	O_WRONLY int = syscall.O_WRONLY //只写模式
    	O_RDWR   int = syscall.O_RDWR   // 读写混合模式
    	// The remaining values may be or'ed in to control behavior.
    	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  // 打开文件时清空文件
    )
    

    前面三种是文件打开模式,后面五种是打开文件之后相应的操作模式;前面三个你只能选择一个,后面可以多选,中间用"|"隔开。

    OpenFile函数的第三个参数是文件的权限,跟linux文件权限一致:

    r ——> 004
    w ——> 002
    x ——> 001
    

    通常情况如果你只是读文件操作,权限是可以被忽略的,第三个参数可以传0。而在写文件的时候,就需要传666,以确保你有足够的权限执行写入。

    2. 写入文件

    上面我们用到了OpenFile,可以指定文件打开的方式,如果使用了只写或者读写模式,表示可以写文件。另外control模式选择的不同对你写文件的影响也是大有不同的,比如:
    |--------------------------------------------------------------------------------
    os.O_RDWR|os.O_CREATE : 文件不存在会新建文件,文件如果存在,会从文件开始处用新内容覆盖原始内容,(如果新内容只有5个字符,原始内容有10个,那么只有开始5个是新内容,后面5个还是以前的内容)

    os.O_RDWR|os.O_APPEND : 本次写入的值会在文件末尾进行append操作,不会覆盖以前的内容。

    os.O_RDWR|os.O_TRUNC : 打开文件的时候先清空文件。
    |-------------------------------------------------------------------------------

    package main
    
    import (
        "fmt"
        "os"
    )
    
    
    func main() {
        openFile, e := os.OpenFile("c:/1.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 777)
        if e != nil {
            fmt.Println(e)
        }
        str := "overwrite to file"
        openFile.WriteString(str)
        openFile.Close()
    }
    

    上面是打开文件写内容,当然我们也可以创建文件写内容:

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    
    func main() {
        f, err := os.Create("c:/1.txt")
        if err != nil {
            fmt.Println(err)
            return
        }
        defer f.Close()
    
        content := map[string]string{
            "hello": "111",
            "world": "222",
            "world1": "333",
            "world2": "444",
        }
        bw := bufio.NewWriter(f)
        for k, v := range content {
            bw.WriteString(k + ":" + v + "
    ")
        }
        bw.Flush()
    }
    

    3. 使用bufio读取文件

    上面演示了按照字节流去读文件的方式,Go还提供了一个io缓冲区:bufio,可以先将文件读取到缓冲区中,然后从缓冲区读取数据:

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    func main() {
        openFile, e := os.OpenFile("c:/1.txt", os.O_RDWR|os.O_CREATE, 777)
        if e != nil {
            fmt.Println(e)
        }
        reader := bufio.NewReader(openFile)
        //按行读取
        for {
           line, _, e := reader.ReadLine()
           if e == io.EOF {
               break
           }
           if e != nil {
               fmt.Println(e)
           }
           fmt.Println(string(line))
        }
        //按照指定分隔符读取
        for{
            s, e := reader.ReadString('
    ')
            fmt.Println(s)
            if e == io.EOF {
                break
            }
            if e != nil {
                fmt.Println(e)
            }
        }
        openFile.Close()
    }
    

    4. 读取压缩文件

    compress包提供了读取压缩文件的功能,支持的压缩文件格式为:bzip2、flate、gzip、lzw 和 zlib。

    archive包提供了tar,zip格式的压缩解压缩功能。

    package main
    
    import (
        "archive/zip"
        "fmt"
        "io"
        "os"
        "strings"
    )
    
    //压缩文件
    //files 文件数组,可以是不同dir下的文件或者文件夹
    //dest 压缩文件存放地址
    func Compress(files []*os.File, dest string) error {
        d, _ := os.Create(dest)
        defer d.Close()
        w := zip.NewWriter(d)
        defer w.Close()
        for _, file := range files {
            err := compress(file, "", w)
            if err != nil {
                return err
            }
        }
        return nil
    }
    
    func compress(file *os.File, prefix string, zw *zip.Writer) error {
        info, err := file.Stat()
        if err != nil {
            return err
        }
        if info.IsDir() {
            prefix = prefix + "/" + info.Name()
            fileInfos, err := file.Readdir(-1)
            if err != nil {
                return err
            }
            for _, fi := range fileInfos {
                f, err := os.Open(file.Name() + "/" + fi.Name())
                if err != nil {
                    return err
                }
                err = compress(f, prefix, zw)
                if err != nil {
                    return err
                }
            }
        } else {
            header, err := zip.FileInfoHeader(info)
            header.Name = prefix + "/" + header.Name
            if err != nil {
                return err
            }
            writer, err := zw.CreateHeader(header)
            if err != nil {
                return err
            }
            _, err = io.Copy(writer, file)
            file.Close()
            if err != nil {
                return err
            }
        }
        return nil
    }
    
    //解压
    func DeCompress(zipFile, dest string) error {
        reader, err := zip.OpenReader(zipFile)
        if err != nil {
            return err
        }
        defer reader.Close()
        for _, file := range reader.File {
            rc, err := file.Open()
            if err != nil {
                return err
            }
            defer rc.Close()
            filename := dest + file.Name
            err = os.MkdirAll(getDir(filename), 0666)
            if err != nil {
                return err
            }
            w, err := os.Create(filename)
            if err != nil {
                return err
            }
            defer w.Close()
            _, err = io.Copy(w, rc)
            if err != nil {
                return err
            }
            w.Close()
            rc.Close()
        }
        return nil
    }
    
    func getDir(path string) string {
        return subString(path, 0, strings.LastIndex(path, "/"))
    }
    
    func subString(str string, start, end int) string {
        rs := []rune(str)
        length := len(rs)
    
        if start < 0 || start > length {
            panic("start is wrong")
        }
    
        if end < start || end > length {
            panic("end is wrong")
        }
    
        return string(rs[start:end])
    }
    
    func main() {
        DeCompress("c:/1.zip","c:/")
    
        f1, err := os.Open("c:/1.txt")
        if err != nil {
            fmt.Println(err)
        }
        defer f1.Close()
        f2, err := os.Open("c:/2.txt")
        if err != nil {
            fmt.Println(err)
        }
        files := []*os.File{f1,f2}
        Compress(files,"c:/")
    }
    

    5.使用ioutil读写文件

    ioutil包是Go官方给用户提供的一个io工具类,提供了一些封装好的方法让我们直接调用。

    package main
    
    import (
        "fmt"
        "io/ioutil"
    )
    
    func main() {
        //读取文件
        bytes, e := ioutil.ReadFile("c:/1.txt")
        if e != nil {
            fmt.Println(e)
        }
        fmt.Println(string(bytes))
    
        //读取文件夹
        infos, e := ioutil.ReadDir("c:/1")
        if e != nil {
            fmt.Println(e)
        }
        for _,v := range infos {
            fmt.Println(v.Name())
        }
    
        //向指定文件写入数据,如果文件不存在,则创建文件,写入数据之前清空文件
        ioutil.WriteFile("c:/1.txt", []byte("xxxxxxxxx"), 666)
    
        //在当前目录下,创建一个以test为前缀的临时文件夹,并返回文件夹路径
        name, e := ioutil.TempDir("c:/2", "tmp")
        fmt.Println(name)
        
        //在当前目录下,创建一个以test为前缀的文件,并以读写模式打开文件,并返回os.File指针
        f, e := ioutil.TempFile("c:/2", "tmpFile")
        f.WriteString("tmp word")
        f.Close()
    
    }
    
  • 相关阅读:
    [小程序]支付宝小程序GET请求数据并展示列表界面
    [小程序] 支付宝小程序使用list时提示元素不存在
    [GO] gin 框架gorm下使用logrus记录sql语句
    [Git] 强制使用远端仓库代码覆盖本地代码
    [PHP]外观/门面/Facade模式-结构型设计模式
    ansible-playbook根据shell判断状态
    ansible Unarchive
    find文件获得绝对文件路径绝对值
    Tomcat和JVM的性能调优总结
    Jenkins内置环境变量的使用
  • 原文地址:https://www.cnblogs.com/rickiyang/p/11074176.html
Copyright © 2011-2022 走看看