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

                                              作者:尹正杰

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

一.文件的读取操作

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("拷贝完成")
}

posted @ 2024-08-01 06:27  尹正杰  阅读(23)  评论(0编辑  收藏  举报