【文件管理| 青训营笔记】

96 阅读3分钟

这是我参与【第五届青训营】伴学笔记创作活动的第六天,此篇概述一下在青训营学习的go文件管理相关的知识。

image.png

文件基础

文件的基本操作

fileInfo, err := os.Stat("")    // 文件传入
if err != nil {
    fmt.Println("err: ", err)
    return
}
// 常用直接调用的函数
fileInfo.Name()   // 文件名
fileInfo.Size()   // 文件大小
fileInfo.Mode()   // 文件权限
fileInfo.ModTime()// 修改时间
fileInfo.IsDir()  // 是否文件夹
fileInfo.Sys()    // 基础数据源接口

文件的权限

r,w,x; 004,002,001分别表示读,写,执行

  1. 符号表示: -xr, -x, -rwxr
  2. 八进制表示: 0755, 0555, 0444, 0666

文件操作

  1. 路径:绝对路径,相对路径

  2. 创建目录

    // 获取父目录
    path.Join(filepath, "..")
    ​
    // 创建一层目录
    err := os.Mkdir(filepath, os.ModePerm)
    if err != nil {
        fmt.Println("err: ", err)
        return
    }
    fmt.Println("文件夹创建成功")
    ​
    // 创建多层目录 os.MkdirAll(filepath, os.ModePerm)
    
  3. 创建文件:file, err := os.Create(filepath)

  4. 打开文件

    file, err := os.Open(filepath)  // 只读模式
    file, err := os.OpenFile(filepath, mode)  // mode 表示读写模式或权限等,如 os.O_RDONLY 或 os.O_CREATE
    
  5. 关闭文件:os.Close()

  6. 删除文件或空目录:os.Remove()

  7. 删除所有:os.RemoveAll()

I/O操作

I/O包

  1. Reader 接口

    // 基础的文件读取操作
    // step1: 
    file, err := os.Open(filename)
    if err != nil {
        fmt.Println("err: ", err)
        return
    }
    // step2:
    defer file.Close()
    // step3:
    bs := make([]byte, 4, 4)
    n, err := file.Read(bs)
    n->  长度
    bs-> 字节
    fmt.Println(string(bs))
    
  2. Writer 接口

    // 基础文件写操作
    bs := []byte{65,66,67,68,69,70}
    n, err := file.Write(bs)
    ​
    // 直接写字符串
    file.WriteString("HelloWorld")
    file.Write([]byte("today"))
    

文件复制

// 用 read 和 write 实现函数
func CopyFile(srcFile, dest) {
    file1, err := os.Open(srcFile)  // 原文件夹
    if err != nil {
        return 0, err
    }
    file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, os.ModePerm)
    // 目标文件夹
    if err != nil {
        return 0, err
    }
    defer file1.Close()
    defer file2.Close()
    // 读写
    bs := make([]byte, 1024, 1024)
    n := -1      // 读取的数据量
    total := 0
    for {
        n, err = file1.Read(bs)
        if err == io.EOF || n == 0 {  // 碰到 EOF 退出循环
            fmt.Println("拷贝完成...")
            break
        }
        else if err != nil {
            fmt.Println("报错了...")
            return total, err
        }
        total += n
        file2.Write(bs[:n])  // 写入数据
    }
    return total, nil
}
// io 包下的 Copy() 方法
func copyFile2(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_CREATE, os.ModePerm)
    if err != nil {
        return 0, err
    }
    defer file1.Close()
    defer file2.Close()
    return io.Copy(file2, file1)  // Copy 函数直接调用
}
// ioutil 包方法 (由于使用一次性读取文件,不适合大文件,容易内存溢出)
func copyFile3(srcFile, destFile string) (int, error) {
    bs, err := ioutil.ReadFile(srcFile)
    if err != nil {
        return 0, err
    }
    err = ioutil.WriteFile(destFile, bs, 0777)
    if err != nil {
        return 0, err
    }
    return len(bs), nil
}

其他方法:CopyN(dest, src, n) 复制 src 中 n 个字节到 dest

CopyBuffer(dest, src, buf) 为指定一个buf 缓冲区, 以这个大小完全复制

断点续传

file.Seek(len, mode)
// len 表示距离
/* mode : 
    io.SeekStart     光标移到距离开始len的位置
    io.SeekCurrent   光标移到距离当前len的位置
    io.SeekEnd       光标移到距离结尾len的位置
*/

bufio 包原理

1674806863954.png 1674807199374.png

作用:将 io 包下的 Reader, Writer 对象进行包装,带缓存的包装,提高读写效率

input := bufio.NewReader(file/os.Stdin)

scanner := bufio.NewScanner(file/os.Stdin)

具体用法略

ioutil 包

  1. data, err := ioutil.ReadFile(filename) 读取文件中的所有数据

  2. ioutil.WriteFile(filename, []byte(data), os.ModePerm) 往文件中写入数据

  3. str := "hahaha"

    newstr := strings.NewReader(str)

    data, err := ioutil.ReadAll(newstr) // 将字符串转换为字节流

  4. 临时目录和临时文件

    dir, err := ioutil.TempDir(dirpath, dirnameprefix)  // 创建临时目录
    file, err := ioutil.TempFile(dir, filenameprefix)   // 创建临时文件
    

便利文件夹

func listFiles(dirname string, level int) {
    fileInfos, err := ioutil.ReadDir(dirname)  // 读入目录下文件
    s := ""
    for i := 0; i < level; i++ {
        s = "  " + s
    }  // 空格,便于层次化目录结构
    if err != nil {
        log.Fatal(err)
    }
    for _, fi := range fileInfos {  // 获取文件
        filename := dirname + "/" + fi.Name()
        fmt.Printf("%s%s\n", s,  filename)
        if fi.IsDir() {
            // 递归调用方法
            listFiles(filename)
        }
    }
}