• Golang: 常用的文件读写操作


    Go 语言提供了很多文件操作的支持,在不同场景下,有对应的处理方式,今天就来系统地梳理一下,几种常用的文件读写的形式。

    一、读取文件内容

    1、按字节读取文件

    这种方式是以字节为单位来读取,相对底层一些,代码量也较大,我们看下面代码:

    // read-bytes.go
    
    package main
    
    import (
        "fmt"
        "io"
        "os"
    )
    
    func main()  {
        file, _ := os.Open("test.txt")
    
        defer file.Close()
    
        // 字节切片缓存 存放每次读取的字节
        buf := make([]byte, 1024)
    
        // 该字节切片用于存放文件所有字节
        var bytes []byte
    
        for {
            // 返回本次读取的字节数
            count, err := file.Read(buf)
    
            // 检测是否到了文件末尾
            if err == io.EOF {
                break;
            }
    
            // 取出本次读取的数据
            currBytes := buf[:count]
    
            // 将读取到的数据 追加到字节切片中
            bytes = append(bytes, currBytes...)
        }
    
        // 将字节切片转为字符串 最后打印出来文件内容
        fmt.Println(string(bytes))
    }
    

    2、结合 ioutil 来读取

    如果我们不想那么麻烦,可以结合 ioutil 来精简上面的代码:

    // read-with-util.go
    
    package main
    
    import (
        "fmt"
        "io/ioutil"
        "os"
    )
    
    func main()  {
        file, _ := os.Open("test.txt")
    
        defer file.Close()
    
        // ReadAll接收一个io.Reader的参数 返回字节切片
        bytes, _ := ioutil.ReadAll(file)
    
        fmt.Println(string(bytes))
    }
    

    由于 os.File 也是 io.Reader 的实现,我们可以调用 ioutil.ReadAll(io.Reader) 方法,将文件所有字节读取出来,省去了使用字节缓存循环读取的过程。

    3、仅使用 ioutil 包来完成读取操作:

    为了进一步简化文件读取操作,ioutil 还提供了 ioutil.ReadFile(filename string) 方法,一行代码搞定读取任务:

    // read-by-util.go
    
    package main
    
    import (
        "fmt"
        "io/ioutil"
    )
    
    func main()  {
        bytes, _ := ioutil.ReadFile("test.txt")
    
        fmt.Println(string(bytes))
    }
    

    4、逐行读取:

    有时候为了便于分析处理,我们希望能够逐行读取文件内容,这个时候可以 Scanner 来完成:

    // read-line-by-line.go
    
    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func main() {
        file, _ := os.Open("test.txt")
    
        defer file.Close()
    
        // 接受io.Reader类型参数 返回一个bufio.Scanner实例
        scanner := bufio.NewScanner(file)
    
        var count int
    
        for scanner.Scan() {
            count++
            
            // 读取当前行内容
            line := scanner.Text()
    
            fmt.Printf("%d %s
    ", count, line)
        }
    }
    

    这简直就是 java.util.Scanner 翻版嘛,并且 Go 语言中的 Scanner 也可以接收不同的输入源,比如 os.Stdin 等。

    上面代码直接打印出了每一行的数据,如果大家想得到最终文件的内容,可以创建一个字符串切片,每次逐行扫描时,将当前行内容追加到切片中即可。

    以上就是几种常用的文件读取方式,当然还有其他更高级的方式,有机会再做总结。

    二、写入文件操作

    1、使用 ioutil 完成写入操作

    上面我们介绍了 ioutil.ReadFile(filename string),与之对应地有 ioutil.WriteFile(filename string, ...) 方法,可以轻松完成写入操作:

    // write-by-util.go
    
    package main
    
    import (
        "io/ioutil"
    )
    
    func main() {
        data := []byte("hello goo
    ")
    
        // 覆盖式写入
        ioutil.WriteFile("test.txt", data, 0664)
    }
    

    我们看到,WriteFile() 方法需要传入三个参数,它的完整签名是:ioutil.WriteFile(filename string, data []byte, perm os.FileMode)。如果文件不存在,则会根据指定的权限创建文件,如果存在,则会先清空文件原有内容,然后再写入新数据。

    需要注意最后一个参数,它是一个无符号 32 位整数,表示当前文件的权限,也是标准的 Unix 文件权限格式。

    Unix 使用 -rwxrwxrwx 这样的形式来表示文件权限,其中:

    • 第1位:文件属性,- 表示是普通文件,d 表示是一个目录
    • 第2-4位:文件所有者的权限
    • 第5-7位:文件所属用户组的权限
    • 第8-10位:其他人的权限

    在权限设置中:

    • r 表示 read,值为 4
    • w 表示 write,值为 2
    • x 表示 exec,值为 1

    下面我们通过 os.FileMode 测试一下:

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func showMode(code int) {
        fmt.Println(os.FileMode(code).String())
    }
    
    func main() {
        showMode(0777)
        showMode(0766)
        showMode(0764)
    }
    

    运行程序,控制台打印如下:

    -rwxrwxrwx
    -rwxrw-rw-
    -rwxrw-r--
    

    2、通过File句柄完成写入操作

    上面我们曾使用过 os.Open(name string) 方法,这个方法是以只读方式打开文件的,os 包还提供了 os.OpenFile(name string, flag int, perm FileMode) 方法,通过指定额外的 读写方式文件权限 参数,使文件操作变得更为灵活。

    其中,flag 有以下几种常用的值:

    • os.O_CREATE: create if none exists 不存在则创建
    • os.O_RDONLY: read-only 只读
    • os.O_WRONLY: write-only 只写
    • os.O_RDWR: read-write 可读可写
    • os.O_TRUNC: truncate when opened 文件长度截为0:即清空文件
    • os.O_APPEND: append 追加新数据到文件

    在打开文件之后,我们可以通过 Write() 和 WriteString() 方法写入数据,最后通过 Sync() 方法将数据持久化到磁盘:

    // write-by-file-descriptor.go
    
    package main
    
    import (
        "fmt"
        "os"
    )
    
    // 打印写入的字节数
    func printWroteBytes(count int) {
        fmt.Printf("wrote %d bytes
    ", count)
    }
    
    func main() {
        // 以指定的权限打开文件
        file, _ := os.OpenFile("test2.txt", os.O_RDWR | os.O_APPEND | os.O_CREATE, 0664)
    
        defer file.Close()
    
        data := []byte("hello go
    ")
    
        // 写入字节
        count, _ := file.Write(data)
    
        printWroteBytes(count)
    
        // 写入字符串
        count, _ = file.WriteString("hello world
    ")
    
        printWroteBytes(count)
    
        // 确保写入到磁盘
        file.Sync()
    }
    

    3、通过bufio包完成写入操作

    这种方式其实是在 File 句柄上做了一层封装,调用方式和上面直接写入非常相似,大家仅做个参考:

    // write-with-bufio.go
    
    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func printWroteBytes(count int) {
        fmt.Printf("wrote %d bytes
    ", count)
    }
    
    func main() {
        file, _ := os.OpenFile("test.txt", os.O_RDWR | os.O_APPEND | os.O_CREATE, 0664)
    
        defer file.Close()
    
        // 获取bufio.Writer实例
        writer := bufio.NewWriter(file)
    
        // 写入字符串
        count, _ := writer.Write([]byte("hello go
    "))
    
        fmt.Printf("wrote %d bytes
    ", count)
    
        // 写入字符串
        count, _ = writer.WriteString("hello world
    ")
    
        fmt.Printf("wrote %d bytes
    ", count)
    
        // 清空缓存 确保写入磁盘
        writer.Flush()
    }
    

    以上就是常用的文件读写方式,今天就总结到这里吧,后续有机会再探讨更多内容。

  • 相关阅读:
    connect: network is unreachable问题的解决
    Linux图形界面与字符界面切换
    Xshell远程连接Linux服务器出错
    demo-placeholder兼容ie8
    Python设计TFTP客户端
    python hashlib、hmac模块
    python time、datetime、random、os、sys模块
    python 字符串和字典
    ssh远程登录时提示access denied
    指针的指针与指针的引用
  • 原文地址:https://www.cnblogs.com/liuhe688/p/11410464.html
Copyright © 2020-2023  润新知