Golang文件操作

文件操作

  • 文件的概念
    文件是数据源(保存数据的地方)的一种,文件最主要的作用就是保存数据.
  • 输入流和输出流
  1. 流:数据在数据源(文件)和程序(内存)之间经历的路径
  2. 输入流:数据从数据源(文件)到程序(内存)的路径
  3. 输出流:数据从程序(内存)到数据源(文件)的路径
  • os.File
    os.File 封装所有文件相关操作,File 是一个结构体
    type File 
    type File struct { 
    // 内含隐藏或非导出字段 
    } 
    //File代表一个打开的文件对象。
  • 文件的基本函数
  1. 新建文件
    func Create(filename string) (file *File, err Error)

根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666的文件,返回的文件对象是可读写的。

    func NewFile(fd uintptr, filename string) *File

根据文件描述符创建相应的文件,返回一个文件对象

  1. 打开文件
    func Open(filename string) (file *File, err error)

Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。
该方法打开一个名称为filename的文件,但是是只读方式,内部实现其实调用了OpenFile。

    func OpenFile(filename string, flag int, perm uint32) (file *File, err Error)

OpenFile主要用来指定参数(os.O_APPEND|os.O_CREATE|os.O_WRONLY)以及文件权限(0666)来打开文件,如果打开成功返回的文件对象将被用作I/O操作,flag是打开的方式,只读、读写等,perm是权限
3. 写文件

    func (file *File) Write(b []byte) (n int, err Error)

写入长度为b字节切片到文件f中,返回写入字节号和错误信息。当n不等于len(b)时,将返回非空的err

    func (file *File) WriteAt(b []byte, off int64) (n int, err Error)

在off偏移量出向文件f写入长度为b的字节

    func (file *File) WriteString(s string) (ret int, err Error)

类似于Write方法,但是写入内容是字符串而不是字节切片

    bufio.NewWriter(w io.Writer) *Writer

    举例:
    writer := bufio.NewWriter(file)
    // 使用for循环写入内容
    for i := 0; i < 3; i++ {
        _, err := writer.WriteString(str) // func (b *Writer) WriteString(s string) (int, error)
        if err != nil {
            fmt.Printf("文件写入出错:%s", err)
        }
    }

缓冲方式写入

    err = ioutil.WriteFile(filePath, content, 0666)
    if err != nil {
        fmt.Printf("写入文件出错:%v", err)
        return
    }

使用ioutil.WriteFile方式写入文件,是将[]byte内容写入文件,如果content字符串中没有换行符的话,默认就不会有换行符,如果文件不存在将按给出的权限创建文件,否则在写入数据之前清空文件。
4. 读文件

func (file *File) Read(b []byte) (n int, err Error)

从文件对象中读取长度为b的字节,返回当前读到的字节数以及错误信息。因此使用该方法需要先初始化一个符合内容大小的空的字节列表。读取到文件的末尾时,该方法返回0,io.EOF

func (file *File) ReadAt(b []byte, off int64) (n int, err Error)

从文件的off偏移量开始读取长度为b的字节。返回读取到字节数以及错误信息。当读取到的字节数n小于想要读取字节的长度len(b)的时候,该方法将返回非空的error。当读到文件末尾时,err返回io.EOF

    bufio.NewReader(rd io.Reader) *Reader

    举例:
    reader := bufio.NewReader(file)
    for {
        line, err := reader.ReadString('\n') // 读到一个换行符就结束
        if err == io.EOF { // io.EOF表示文件的末尾
            break
        }
    }

缓冲方式读取(默认缓冲区4096字节)

    func ReadFile(filename string) ([]byte, error)

    举例:
    content, err := ioutil.ReadFile(filePath)
    if err != nil {
        // log.Fatal(err)
        fmt.Printf("读取文件出错:%v", err)
    }

使用 io/ioutil.ReadFile 方法一次性将文件读取到内存中
5. 判断文件是否存在

golang判断文件或文件夹是否存在的方法为使用 os.Stat() 函数返回的错误值进行判断:

  1. 如果返回的错误为 nil,说明文件或文件夹存在;
  2. 如果返回的错误类型使用 os.IsNotExist() 判断为 true,说明文件或文件夹不存在;
    3.如果返回的错误为其他类型,则不确定是否存在。
  1. 关闭文件
    func (f *File) Close() error

Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。
7. 拷贝文件

    func Copy(dst Writer, src Reader) (written int64, err error)

    举例:
    // 将 srcFilePath 拷贝到 dstFilePath
    func CopyFile(dstFilePath string, srcFilePath string) (written int64, err error) {
        // 打开srcFilePath
        srcFile, err := os.Open(srcFilePath)
        if err != nil {
            fmt.Printf("打开文件出错:%s\n", err)
            return
        }
        defer srcFile.Close()
        // 通过 bufio/NewReader,传入 srcFile,获取到 reader
        reader := bufio.NewReader(srcFile)
        // 打开dstFilePath
        dstFile, err := os.OpenFile(dstFilePath, os.O_WRONLY | os.O_CREATE, 0666)
        if err != nil {
            fmt.Printf("打开文件出错:%s\n", err)
            return
        }
        defer dstFile.Close()
        // 通过 bufio/NewWriter,传入 dstFile,获取到 writer
        writer := bufio.NewWriter(dstFile)
        return io.Copy(writer, reader)
    }
    func main() {
        srcFilePath := "e:/a.mp4"
        dstFilePath := "f:/b.mp4"
        _, err := CopyFile(dstFilePath, srcFilePath)
        if err != nil {
            fmt.Printf("拷贝文件出错:%s", err)
        }
        fmt.Println("拷贝文件完成")
    }

将src的数据拷贝到dst,直到在src上到达EOF或发生错误。返回拷贝的字节数和遇到的第一个错误。

  1. 删除文件
    func Remove(name string) Error

调用该函数就可以删除文件名为name的文件
9. 断点续传

    package main
    import (
        "os"
        "io"
        "net/http"
        "net/url"
        "strconv"
        )

    func main() {
        f, err := os.OpenFile("./chrome_installer.exe", os.O_RDWR|os.O_CREATE, 0666) //O_RDWR|O_CREATE,也就是文件不存在的情况下就建一个空文件,因为windows下还有BUG,如果使用这个O_CREATE,就会直接清空文件,所以windows不用这个标志,你自己事先建立好文件。
        if err != nil {
            panic(err)
        }
        stat, err := f.Stat() //获取文件状态
        if err != nil {
            panic(err)
        }
        f.Seek(stat.Size(), 0) //把文件指针指到文件末,当然你说为何不直接用 O_APPEND 模式打开,没错是可以。我这里只是试验。
        //f.Seek(int64(os.O_APPEND), 0)
        url1 := "http://dl.google.com/chrome/install/696.57/chrome_installer.exe"
        var req http.Request
        req.Method = "GET"
        //req.UserAgent = UA  //客户端信息字符串,不过我加上UserAgent,一直报错,不知道怎么回事,暂时不用它
        req.Close = true
        req.URL, err = url.Parse(url1)
        if err != nil {
            panic(err)
        }
        header := http.Header{}
        header.Set("Range", "bytes="+strconv.FormatInt(stat.Size(), 10)+"-")
        req.Header = header
        resp, err := http.DefaultClient.Do(&req)
        if err != nil {
            panic(err)
        }
        written, err := io.Copy(f, resp.Body)
        if err != nil {
            panic(err)
        }
        println("written: ", written)
    }
  • 常用操作
  1. 遍历一个目录
    func main() {
        fmt.Println("请输入一个目录的路径:")
        var path string
        _, _ = fmt.Scan(&path)
        // 打开目录
        f, err := os.OpenFile(path, os.O_RDONLY, os.ModeDir)
        if err != nil {
            fmt.Printf("Open file failed:%s.\n", err)
            return
        }
        defer f.Close()
        // 读取目录
        info, err := f.Readdir(-1) // -1 表示读取目录中所有目录项
        // 遍历返回的切片
        for _, fileInfo := range info {
            if fileInfo.IsDir() {
                fmt.Printf("%s是一个目录\n", fileInfo.Name())
            } else {
                fmt.Printf("%s是一个文件\n", fileInfo.Name())
            }
        }
    }
  1. 统计一个文件中含有的英文、数字、空格以及其他字符数量。
    // 定义一个结构体,用于保存统计结果
    type CharCount struct {
        AlphaCount     int // 记录英文个数
        NumCount     int // 记录数字的个数
        SpaceCount     int // 记录空格的个数
        OtherCount     int // 记录其它字符的个数
    }

    func main() {
        // 思路: 打开一个文件, 创一个 reader
        // 每读取一行,就去统计该行有多少个 英文、数字、空格和其他字符
        // 然后将结果保存到一个结构体
        filePath := "e:/a.txt"
        file, err := os.Open(filePath)
        if err != nil {
            fmt.Printf("打开文件出错:%s\n", err)
            return
        }
        defer file.Close()
        // 定义一个 CharCount 实例
        var count CharCount
        //创建一个Reader
        reader := bufio.NewReader(file)
        // 开始循环的读取文件的内容
        for {
            line, err := reader.ReadString('\n')
            if err == io.EOF { // 读到文件末尾就退出
                break
            }
            // 遍历每一行(line),进行统计
            for _, v := range line {
                switch {
                    case v >= 'a' && v <= 'z':
                        fallthrough // 穿透
                    case v >= 'A' && v <= 'Z':
                        count.AlphaCount++
                    case v >= '0' && v <= '9':
                        count.NumCount++
                    case v == ' ' || v == '\t':
                        count.SpaceCount++
                    default :
                        count.OtherCount++
                }
            }
        }
        // 输出统计的结果看看是否正确
        fmt.Printf("字符的个数为:%v\n数字的个数为:%v\n空格的个数为:%v\n其它字符个数:%v\n",
            count.AlphaCount, count.NumCount, count.SpaceCount, count.OtherCount)
    }
posted @ 2020-09-03 14:20  养诚  阅读(402)  评论(0编辑  收藏  举报