Go Book / 1 Go Basics / 20 Go 文件 I O (一):文件操作

20 Go 文件 I O (一):文件操作

一、文件处理概述

基本所有语言都支持一些文件资源的IO操作,所谓IO即对资源的读写。在类Unix的设计哲学中,一切资源皆为文件。在IO中你会常见到一些Write、Read、Writer、Reader的概念,有时你会对一些读写主体产生混淆,这里可以明晰一下:

一般读写的主体都为运行的程序,程序运行于内存中,而资源一般位于程序主体的外部,多以Read一般理解为读入,将外部资源读入程序内存,而Write则相反,指数据有程序内存写出到外部的磁盘资源。当然所谓外部不一定指磁盘,这里的外部是相对程序主体而言的。而Reader、Writer就好理解了,它们是抽象化的读写操作主体,如Read操作是通过Reader实现的,Reader内部提供Read方法。另外,IO操作的数据单位一般都为byte,你会看到go的标准库中,许多数据IO都是通过[]byte传输的。

理清以上比较容易混淆的概念再去阅读Go的IO相关包源码就好理解了。

二、Go IO标准包

  • os包

一个平台无关的操作系统接口,提供一些系统资源的调用功能,如文件、目录打开关闭,环境设置、状态信息等。

  • io包

提供了对I/O原语的基本接口。本包的基本任务是包装这些原语已有的实现(如os包里的原语),使之成为共享的公共接口,这些公共接口抽象出了泛用的函数并附加了一些相关的原语的操作。与os包配合,所谓io就是一些读写的操作。

  • io/ioutil包

基于io包实现一些实用的工具函数,由于封装性较好,使用简单,所以日常开发该包使用多一些。

  • bufio包

bufio包实现了有缓冲的I/O。它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象。如操作的资源较大,一般建议使用带缓冲的bufio。

三、文件操作演示

1.基本文件读写

示例一:打开一个文件简单操作,打开后延时关闭。

func BaseFileOperation01() {
	file, err := os.Open("/path/to/file_operation_demo_text.txt")
	if err != nil {
		fmt.Println("文件打开错误,err=", err)
		return
	}

	//完成后延时1s关闭
	defer func() {
		time.Sleep(time.Second)
		file.Close()
	}()
	info, _ := file.Stat()

	fmt.Println(info.Name())
}

示例二:以只读方式打开一个文件创建缓冲读取器,逐行读到末尾。

func BaseFileOperation02() {
	file, err := os.OpenFile("/path/to/file_operation_demo_text.txt", os.O_RDONLY, 0666)
	if err != nil {
		fmt.Println("文件打开错误,err=", err)
		return
	}
	defer file.Close() //完成后关闭

	//创建缓冲读取器
	reader := bufio.NewReader(file)
	for {
		readString, err := reader.ReadString('\n') //以换行符为间隔分箱读取
		if err != nil {
			if e == io.EOF {
				break
			}

			fmt.Println("缓冲读取错误,err=", err)
			return
		}

		fmt.Println(readString)
	}

	fmt.Println("缓冲读取文件完成")
}

示例三:使用ioutil包对文件进行简易读取

func BaseFileOperation03() {
	bytes, err := ioutil.ReadFile("/path/to/file_operation_demo_text.txt")
	if err != nil {
		fmt.Println("文件打开错误,err=", err)
		return
	}

	fmt.Println(string(bytes))
}

示例四:以创写追加或创写覆盖方式打开一个文件,缓冲式写出几行数据,倒干缓冲区后退出

func BaseFileOperation04() {
	openFile, err := os.OpenFile("/path/to/file_operation_demo_text111.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if e != nil {
		fmt.Println("文件打开错误,err=", err)
		return
	}
	defer openFile.Close()

	//创建一个缓冲桶
	writer := bufio.NewWriter(openFile)
	writer.WriteString("这是新插入的信息1\n")
	writer.WriteString("这是新插入的信息2\n")
	writer.WriteString("这是新插入的信息3\n")
	writer.WriteString("这是新插入的信息4\n")

	flush := writer.Flush()

	fmt.Println("缓冲写入数据完成!!!清空缓冲状态:", flush)
}

示例五:使用os包的状态检测结合os.IsNotExist(err)判断文件是否存在。

func BaseFileOperation05() {
	_, err := os.Open("/path/to/file_operation_demo_text11.txt")
	exist1 := os.IsNotExist(err)
	fmt.Println("文件是否不存在:", exist1)

	exist2 := os.IsExist(err)
	fmt.Println("文件是否存在:", exist2)
}

示例六:使用ioutil包进行建议文件写出。

func BaseFileOperation06() {
	//
	stringByte := []byte("这是一次用ioutil包的简易写出操作\n")
	ioutil.WriteFile("/path/to/file_operation_demo_text111.txt", stringByte, 0666)

	fmt.Println("简易写出完成!")

}

2.文件拷贝

示例七:ioutil包简单拷贝

func BaseFileOperation07() {
	bytes, err := ioutil.ReadFile("/path/to/file_operation_demo_text111.txt")
	if e != nil {
		fmt.Println("文件读取错误,err=", err)
		return
	}

	err = ioutil.WriteFile("/path/to/file_operation_demo_text222.txt", bytes, 0666)
	if err != nil {
		fmt.Println("文件写入错误,err=", err)
		return
	}

	fmt.Println("文件拷贝完成!!!")
}

示例八:io.Copy进行文件拷贝

func BaseFileOperation08() {
	//只读模式打开文件
	src, err := os.OpenFile("/path/to/file_operation_demo_text.txt", os.O_RDONLY, 0666)
	if err != nil {
		fmt.Println("文件打开错误,err=", err)
		return
	}
	defer src.Close()

	//只写模式打开创建文件
	dst, err := os.OpenFile("/Users/fun/Code/mygo/src/mydemo/text/file_operation_demo_text_copy.txt", os.O_CREATE|os.O_WRONLY, 0666)
	if err != nil {
		fmt.Println("文件写入错误,err=", err)
		return
	}
	defer dst.Close()

	written, err := io.Copy(dst, src)
	if err != nil {
		fmt.Println("ioutil拷贝操作错误!!!")
		return
	}

	fmt.Println("ioutil拷贝操作完成:", written)
}

示例九:使用缓冲1K的缓冲区配合缓冲读写器进行图片拷贝

func BaseFileOperation09() {
    src, err := os.OpenFile("/path/to/myimage.jpg", os.O_RDONLY, 0666)
	if err != nil {
		fmt.Println("文件打开错误,err=", err)
		return
	}
	defer src.Close()

	//只写模式打开创建文件
	dst, err := os.OpenFile("/path/to/myimage_copy.jpg", os.O_CREATE|os.O_WRONLY, 0666)
	if err != nil {
		fmt.Println("文件写入错误,err=", err)
		return
	}
	defer dst.Close()

	//创建缓冲区[[byte
	var n int = 0
	bufbytes := make([]byte, 1024)
	reader := bufio.NewReader(src)
	writer := bufio.NewWriter(dst)

	for {
		n++
		_, err = reader.Read(bufbytes)
		if err != nil {
			if err == io.EOF {
				fmt.Println("文件读到末尾!", n)
				break
			}
			fmt.Println("读取图片到缓冲区错误:", err)
		}

		_, err = writer.Write(bufbytes)
		if err != nil {
			fmt.Println("读取图片到缓冲区错误:", err)
		}
	}
}