Golang语言文件操作快速入门篇

简介: 这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。

                                              作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.文件的读取操作

1.什么是文件

计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件和二进制文件。

文件是保存数据的地方,是数据源的一种,比如大家经常使用的word文件,txt文件,Excel,jpg,png,mp3,mp4,rmvb等都是文件。

文件最主要的做哟合格就是保存数据,它既可以保存一张图片,也可以保存视频,声音等等。

2.IO流类型概述

如上图所示,IO(Input/Output)流是程序和数据源沟通的桥梁,IO流分为输入流和输出流两个不同的方向。

输入流一般指的是程序读取源文件的场景。

输出流一般指的是程序写入数据到目标文件的场景。

3.文件的基本操作

3.1 打开和关闭文件

package main

import (
    "fmt"
    "os"
)

func main() {

    // 1.打开文件
    file, err := os.Open("/etc/hosts")

    if err != nil {
        fmt.Printf("打开文件出错, err= %v\n", err)
    }

    // 2.在程序退出前一定要关闭文件以释放资源
    defer file.Close()

    // 3.打开文件若没错,则可以对文件进行一系列的操作
    fmt.Printf("文件对象: %v\n", file)
}

3.2 带缓冲大小读取文件内容

package main

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

func main() {
    // 只读方式打开当前目录下的hosts文件
    file, err := os.Open("/etc/hosts")
    if err != nil {
        fmt.Println("打开文件失败!, err = ", err)
        return
    }

    // 为了防止文件忘记关闭导致内存泄漏,我们通常使用defer注册文件关闭语句。
    defer file.Close()

    // 定义一个缓冲区的字节切片,此处咱们可以一次性读取4096个字节大小数据区域。
    var cache = make([]byte, 4096)

    /*
        使用Read方法读取数据,需要专递一个字节切片,该切片大小表示一次性读取的文件内容的大小。
            - 1.当我们传递的字节切片大小较小时,尽管没有读取完文件的所有内容,也不会读取超出的内容哟。
            - 2、当我们传递的字节切片大小较大时,会将文件的内容全部读取出来,并不会重复读取文件的内容哟~
    */
    n, err := file.Read(cache)
    if err == io.EOF {
        fmt.Println("文件读完了")
        return
    }
    if err != nil {
        fmt.Println("read file failed, err:", err)
        return
    }

    fmt.Printf("读取了%d字节数据\n", n)

    fmt.Printf("文件内容:\n%s", string(cache[:n]))
}

3.3 循环读取

package main

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

func main() {
    file, err := os.Open("/etc/hosts")
    if err != nil {
        fmt.Println("open file failed!, err:", err)
        return
    }
    defer file.Close()

    var content []byte
    var tmp = make([]byte, 128)

    // 使用for循环读取文件中的所有数据。
    for {
        // 一次性读取的128字节的大小
        buf, err := file.Read(tmp)
        if err == io.EOF {
            fmt.Println("文件读完了")
            break
        }
        if err != nil {
            fmt.Println("文件读取失败,错误:", err)
            return
        }

        // 每次读取buf大小后都追加到content切片中
        content = append(content, tmp[:buf]...)
    }

    // 将所有的内容读取到content切片后,再统一打印
    fmt.Printf("文件内容:\n%s", string(content))
}

4.ioutil包一次性读取小文件

4.1 ioutil包概述

读取文件的内容并显示在终端(使用ioutil一次性将整个文件读入到内存中),这种方式适用于文件不大的情况。

相关方法的函数有"ioutil.ReadFile"。

4.2 ioutil读取整个文件

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    // "io/ioutil"包的ReadFile方法能够读取完整的文件,只需要将文件名作为参数传入。
    content, err := ioutil.ReadFile("/etc/hosts")
    if err != nil {
        fmt.Println("读取文件出错, err:", err)
        return
    }

    // 读取文件的内容并显示在终端(使用ioutil一次性将整个文件读入到内存中),这种方式适用于文件不大的情况。
    fmt.Printf("文件内容: \n%v", string(content))
}

5.bufio包按行读取文件

package main

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

func main() {

    // 打开文件
    file, err := os.Open("/etc/hosts")
    if err != nil {
        fmt.Println("文件打开失败, err=", err)
        return
    }

    // 当函数退出是,让file关闭,防止内存泄漏;
    defer file.Close()

    // 创建一个IO流,bufio是在file的基础上封装了一层API,支持更多的功能。
    reader := bufio.NewReader(file)

    // 读取操作
    for {
        // 按行读取,注意是字符'\n'。
        line, err := reader.ReadString('\n')

        // 表示已经读取到文件的结尾
        if err == io.EOF {
            if len(line) != 0 {
                fmt.Println(line)
            }
            fmt.Println("文件读完了")
            break
        }
        if err != nil {
            fmt.Println("读取文件失败, err:", err)
            return
        }

        //  如果没有读取到文件结尾的话,就正常输出文件内容即可。
        fmt.Print(line)
    }

    //
    fmt.Println("文件读取成功,程序运行结束...")
}

二.文件的写入操作

1.文件的打开模式

模式 含义
os.O_RDONLY 只读模式打开文件
os.O_WRONLY 只写模式打开文件
os.O_RDWR 读写模式打开文件
os.O_APPEND 写操作时将数据附加到文件尾部
os.O_CREATE 创建文件
os.EXCL os.OCREATE配合使用,文件必须不存在
os.SYNC 打开文件用于同步I/O
os.O_TRUNC 如果文件存在,则打开文件时先清空再打开
os.OpenFile()函数能够以指定模式打开文件,从而实现文件写入相关功能。
    func OpenFile(name string, flag int, perm FileMode) (*File, error) {
        ...
    }

相关参数说明:
    - name:
        要打开的文件名 
    - flag:
        打开文件的模式,常见的模式如上表所示。
    - perm:
        文件权限,一个八进制数。r(读)04,w(写)02,x(执行)01。

2.Write和WriteString

package main

import (
    "fmt"
    "os"
)

func main() {
    // 以只写的模式打开文件
    file, err := os.OpenFile("blog.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)

    if err != nil {
        fmt.Println("文件打开失败, err= ", err)
        return
    }

    defer file.Close()

    str := "博客地址: https://www.cnblogs.com/yinzhengjie\n\n"

    //写入字节切片数据
    file.Write([]byte(str))

    //直接写入字符串数据
    file.WriteString("Go视频教学地址: https://www.bilibili.com/video/BV1bwhve7EPJ/\n")

}

3.bufio.NewWriter写入文件

package main

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

func main() {

    // 以只写的模式打开文件
    file, err := os.OpenFile("./yinzhengjie.log", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)

    // 判断文件是否打开失败
    if err != nil {
        fmt.Println("open file failed, err:", err)
        return
    }

    // 及时将文件关闭,防止内存泄漏
    defer file.Close()

    // 写入操作,获取一个IO流,带缓冲区的输出流
    writer := bufio.NewWriter(file)

    // 将数据写入缓冲区
    for i := 0; i < 10; i++ {
        writer.WriteString("博客地址: https://www.cnblogs.com/yinzhengjie\n")
    }

    // 将缓冲区的数据刷新到磁盘
    writer.Flush()

    // tips: 查看文件打开模式,需要懂Linux基础知识
    mode := os.FileMode(0644).String()
    fmt.Printf("mode: 0644 = %s\n", mode)

}

4.WriteFile

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    str := "{\"尹正杰博客地址\": \"https://www.cnblogs.com/yinzhengjie\"}"

    // ioutil.WriteFile写入文件时,若文件已存在或者有内容,会直接将源文件清空哟~
    err := ioutil.WriteFile("./blog.json", []byte(str), 0666)

    if err != nil {
        fmt.Println("文件打开失败,错误 = ", err)
        return
    }

}

三.文件的复制操作

1.拷贝文件内容案例

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    // 1.定义需要拷贝的源文件
    srcFile := "/etc/hosts"

    // 2.定义拷贝到目标文件路径
    destFile := "./hosts"

    // 3.对源文件进行读取数据
    content, err := ioutil.ReadFile(srcFile)
    if err != nil {
        fmt.Printf("文件读取失败: err = %s\n", err)
        return
    }

    // 4.将读取到的数据写入目标文件
    err = ioutil.WriteFile(destFile, content, 0644)

    if err != nil {
        fmt.Printf("文件写入失败, err=%v\n", err)
    }

    fmt.Printf("'%s'文件拷贝完成\n", srcFile)
}

2.借助io.Copy()实现一个拷贝文件函数

package main

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

// CopyFile 拷贝文件函数
func CopyFile(dstFile, srcFile string) (written int64, err error) {

    // 以读方式打开源文件
    src, err := os.Open(srcFile)
    if err != nil {
        fmt.Printf("打开%s文件失败, err = %v\n", srcFile, err)
        return
    }
    defer src.Close()

    // 以写|创建的方式打开目标文件
    dest, err := os.OpenFile(dstFile, os.O_WRONLY|os.O_CREATE, 0644)
    if err != nil {
        fmt.Printf("打开%s文件失败, err = %v\n", dstFile, err)
        return
    }
    defer dest.Close()

    //调用io.Copy()拷贝内容文件内容
    return io.Copy(dest, src)
}

func main() {
    _, err := CopyFile("./hosts", "/etc/hosts")
    if err != nil {
        fmt.Println("拷贝文件失败,err = ", err)
        return
    }

    fmt.Println("拷贝完成")
}
目录
相关文章
|
14天前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
47 4
Golang语言之管道channel快速入门篇
|
14天前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
42 3
Golang语言之gRPC程序设计示例
|
14天前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
37 4
|
14天前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
23 4
Golang语言goroutine协程篇
|
14天前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
20 3
Golang语言之Prometheus的日志模块使用案例
|
14天前
|
JSON Go 数据格式
Golang语言结构体链式编程与JSON序列化
这篇文章是关于Go语言中结构体链式编程与JSON序列化的教程,详细介绍了JSON格式的基本概念、结构体的序列化与反序列化、结构体标签的使用以及如何实现链式编程。
21 4
|
14天前
|
Go
Golang语言结构体(struct)面向对象编程进阶篇(封装,继承和多态)
这篇文章是关于Go语言中结构体(struct)面向对象编程进阶篇的教程,涵盖了Go语言如何实现封装、继承和多态,以及结构体内存布局的相关概念和案例。
27 4
|
14天前
|
Go
Golang语言基础之接口(interface)及类型断言
这篇文章是关于Go语言中接口(interface)及类型断言的详细教程,涵盖了接口的概念、定义、实现、使用注意事项以及类型断言的多种场景和方法。
22 4
|
14天前
|
Go
Golang语言错误处理机制
这篇文章是关于Golang语言错误处理机制的教程,介绍了使用defer结合recover捕获错误、基于errors.New自定义错误以及使用panic抛出自定义错误的方法。
36 3
|
14天前
|
Go
Golang语言之函数(func)进阶篇
这篇文章是关于Golang语言中函数高级用法的教程,涵盖了初始化函数、匿名函数、闭包函数、高阶函数、defer关键字以及系统函数的使用和案例。
16 3
Golang语言之函数(func)进阶篇