文件操作

os 包提供了平台无关的操作系统功能接口。尽管错误处理是 go 风格的,但设计是 Unix 风格的;所以,失败的调用会返回 error 而非错误码。通常 error 里会包含更多信息。例如,如果使用一个文件名的调用(如 Open、Stat)失败了,打印错误时会包含该文件名,错误类型将为 *PathError,其内部可以解包获得更多信息。

os 包规定为所有操作系统实现的接口都是一致的。有一些某个系统特定的功能,需要使用 syscall 获取。实际上,os 依赖于 syscall。在实际编程中,我们应该总是优先使用 os 中提供的功能,而不是 syscall

带缓冲读取

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    file, err := os.Open("/Users/yangsx/Desktop/helloworld.txt") // 返回一个文件对象/文件指针/文件句柄
    defer file.Close() // 关闭File句柄

    if err != nil {
        fmt.Println("open file err: ", err)
    }

    // 创建一个*Reader,默认带大小4096字节的缓冲区
    reader := bufio.NewReader(file)
    // 循环读取文件内容
    for {
        str, err := reader.ReadString('\n') // 读取到换行符就结束
        if err == io.EOF { // 如果读取到文件末尾
            break
        }
        // 输出该行
        fmt.Print(str) // 会把换行符打印
    }
    fmt.Println("----文件读取结束----")
}

一次全文读取

1.16后,ioutil实际上调用os.ReadFile()函数,推荐直接使用os.ReadFile()函数

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    // 返回字节数组
    bs, err := ioutil.ReadFile("/Users/yangsx/Desktop/helloworld.txt")
    if err != nil {
        fmt.Println("读取文件失败:", err)
    }
    fmt.Printf("%s", bs)
}

打开文件的方式

使用func OpenFile(name string, flag int, perm FileMode) (file *File, err error)函数打开文件并指定打开模式:

// flag,打开方式,多个可以组合使用  os.O_RDWR | os.APPEND
const (
    O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
    O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
    O_RDWR   int = syscall.O_RDWR   // 读写模式打开文件
    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  // 如果可能,打开时清空文件
)

// 文件权限
const (
    // 单字符是被String方法用于格式化的属性缩写。
    ModeDir        FileMode = 1 << (32 - 1 - iota) // d: 目录
    ModeAppend                                     // a: 只能写入,且只能写入到末尾
    ModeExclusive                                  // l: 用于执行
    ModeTemporary                                  // T: 临时文件(非备份文件)
    ModeSymlink                                    // L: 符号链接(不是快捷方式文件)
    ModeDevice                                     // D: 设备
    ModeNamedPipe                                  // p: 命名管道(FIFO)
    ModeSocket                                     // S: Unix域socket
    ModeSetuid                                     // u: 表示文件具有其创建者用户id权限
    ModeSetgid                                     // g: 表示文件具有其创建者组id的权限
    ModeCharDevice                                 // c: 字符设备,需已设置ModeDevice
    ModeSticky                                     // t: 只有root/创建者能删除/移动文件
    // 覆盖所有类型位(用于通过&获取类型位),对普通文件,所有这些位都不应被设置
    ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
    ModePerm FileMode = 0777 // 覆盖所有Unix权限位(用于通过&获取类型位)
)

一次性写入

实际调用os.WriteFile()函数

package main

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

func main() {
    str := "hello"
    // 覆盖写入一次性写入字符串
    err := ioutil.WriteFile("/Users/yangsx/Desktop/helloworld.txt", []byte(str), 0666)
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Println("写入成功")
}

带缓冲追加写入

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    file, err := os.OpenFile("/Users/yangsx/Desktop/helloworld.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    defer file.Close()
    if err != nil {
        fmt.Println("打开文件出错:", err)
    }
    // 写入数据
    str := "你好,世界\n"
    // 使用带缓存的 *Writer
    writer := bufio.NewWriter(file)
    for i := 0; i < 5; i++ {
        writer.WriteString(str)
    }
    // 因为writer是带缓存的,需要使用flush函数真正写入到磁盘中
    writer.Flush()

    fmt.Println("写入数据成功")
}

覆盖写入

使用选项, os.O_TRUNC 清空文件

判断文件状态

判断文件/文件夹是否存在:

// Stat函数就像linux下的stat命令,该函数会返回一个FileInfo struct
func PathExist(path string) (bool, error){
    _, err := os.Stat(path)
    if err == nil {
        return true, nil // 没有错误,说明文件/文件夹一定存在
    }
    if os.IsNotExist(err) { // 如果错误信息是文件不存在,则说明文件/文件夹一定不存在
        return false, nil
    }
    return false, err
}

获取文件状态:

package main

import (
    "fmt"
    "log"
    "os"
)

func main() {
    fi, err := os.Stat("/Users/yangsx/Desktop/helloworld.txt")
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Printf(`文件名称为:%s, 
文件大小为: %d,
是否是文件夹: %t,
文件的Mode: %d
`, fi.Name(), fi.Size(), fi.IsDir(), fi.Mode())
}

文件拷贝

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    src := "/Users/yangsx/Desktop/helloworld.txt"
    dst := "/Users/yangsx/Desktop/h.txt"

    srcF, err := os.OpenFile(src, os.O_RDONLY, 0666)
    defer srcF.Close()
    if err != nil {
        fmt.Println("打开src失败: ", err)
        return
    }
    dstF, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
    defer dstF.Close()
    if err != nil {
        fmt.Println("打开dst失败: ", err)
        return
    }

    // 构建reader 和 writter
    reader := bufio.NewReader(srcF)
    writer := bufio.NewWriter(dstF)

    // 调用拷贝方法
    wi, err := io.Copy(writer, reader)
    if err != nil {
        fmt.Println("拷贝失败 ", err)
        return
    }
    fmt.Println("拷贝成功,字节数:", wi)
}

最后更新于