Skip to content

文件操作

打开和关闭文件

在 Go 语言中使用os.Open()可以打开一个文件,返回一个文件指针*file和错误信息err,对得到的文件指针调用close()方法即可关闭文件。

如下:

plain
package main

import (
	"fmt"
	"os"
)

func main() {
	file, _ := os.Open("./main.go")
	fmt.Printf("%T\n", file)
	file.Close()
}

为了防止文件忘记关闭,我们通常使用 defer 注册文件关闭语句。

如下:

plain
package main

import (
	"fmt"
	"os"
)

func main() {
	file, _ := os.Open("./main.go")
	fmt.Printf("%T\n", file)
	defer file.Close()
}

读取文件

file.read()

read方法定义如下:

plain
func (f *File) Read(b []byte) (n int, err error)

该方法接受一个字节类型的参数,返回读取的字节数和可能的错误,读到文件末尾会返回0io.EOF

如下:

go
package main

import (
	"fmt"
	"os"
)

func main() {
	file, err := os.Open("./main.go")
	if err != nil {
		fmt.Printf("File Open failed.err:%s\n", err)
		return
	}
	defer file.Close()
	// 定义读取的字节数
	tmp := make([]byte, 128)
	// 按字节读取文件
	n, err := file.Read(tmp)
	if err != nil {
		fmt.Printf("File Read Failed.err:%s\n", err)
		return
	}
	// 打印读取的字节数
	fmt.Println(n)
	// 打印读取的内容
	fmt.Println(string(tmp[:n]))
}

上面这种读取方式是按设定的字节读取,如果文本中总字节数少于设定的,那么就可以把文本全部读取出来,如果文本总字节数大于设定的字节数,那么文本就不能被全部读取。

这个时候可以使用循环来读取所有文本,如下:

go
package main

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

func main() {
	file, err := os.Open("./main.go")
	if err != nil {
		fmt.Printf("File Open failed.err:%s\n", err)
		return
	}
	defer file.Close()
	// 定义读取的字节数
	tmp := make([]byte, 128)
	for {
		// 按字节读取文件
		n, err := file.Read(tmp)
		// 如果文件已经读完了,就退出
		if err == io.EOF {
			// fmt.Printf("文件读完了\n")
			break
		}
		if err != nil {
			fmt.Printf("File Read Failed.err:%s\n", err)
			return
		}
		// 打印读取的内容
		fmt.Print(string(tmp[:n]))
	}
}

bufio 读取文件

bufio是带缓存功能的 I/O 操作。用其读取文件的示例如下:

go
package main

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

func main() {
	// 打开文件
	file, err := os.Open("./main.go")
	if err != nil {
		fmt.Printf("Open File Failed.err:%s\n", err)
		return
	}
	defer file.Close()
	// 返回一个新的reader,用NewReader有默认大小
	reader := bufio.NewReader(file)
	// 用循环逐行读取文件
	for {
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			// fmt.Printf("File Has Been Read\n")
			break
		}
		if err != nil {
			fmt.Printf("Read File Failed.err:%s\n", err)
		}
		fmt.Print(line)
	}
}

上面是用的bufio.NerReader()来获取一个新的reader,再用这个对象来读取文件的。除此之外还可以使用bufio.NewReaderSize来获取一个新的reader,不同之处在于NewReaderSize可以设置缓冲区的大小,语法如下:

go
reader := bufio.NewReaderSize(fileObj, size)

ioutil 读取整个文件

io/ioutil包的ReadFile方法能够读取完整的文件,只需要将文件名作为参数传入。

go
package main

import (
	"fmt"
	"io/ioutil"
)

func main() {
	content, err := ioutil.ReadFile("./main.go")
	if err != nil {
		fmt.Printf("Read File Failed.err:%s\n", err)
		return
	}
	fmt.Println(string(content))
}

写入文件

os.OpenFile()函数能够以指定模式打开文件,从而实现文件写入相关功能。

go
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
	...
}

其中:

name:要打开的文件名 flag:打开文件的模式。 模式有以下几种:

含义模式
只写os.O_WRONLY
创建文件os.O_CREATE
只读os.O_RDONLY
读写os.O_RDWR
清空os.O_TRUNC
追加os.O_APPEND

perm:文件权限,一个八进制数。r(读)04,w(写)02,x(执行)01。

比如:

go
file,err := os.OpenFile("xx.txtx",os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)

Write 和 WriteString

Write写入的是字节切片数据,WriteString写入的是字符串数据。

如下:

go
package main

import (
	"fmt"
	"os"
)

func main() {
	file, err := os.OpenFile("a.txt", os.O_APPEND|os.O_CREATE, 0644)
	if err != nil {
		fmt.Printf("Open File Failed.err:%s\n", err)
		return
	}
	defer file.Close()
	// 写入
	str := "牛逼的Go语言\n"
	// 用Write写入
	file.Write([]byte(str))
	// 用WriteString写入
	file.WriteString(str)
}

bufio 写入文件

使用bufio.NewWriter()写入文件,需要在最后Flush()

如下:

go
package main

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

func main() {
	file, err := os.OpenFile("b.txt", os.O_APPEND|os.O_CREATE, 0644)
	if err != nil {
		fmt.Printf("Open File Failed.err:%s\n", err)
		return
	}
	defer file.Close()
	// 用bufio.NewWrite返回一个writer
	writer := bufio.NewWriter(file)
	writer.WriteString("这是一个bufio的写入测试")
	writer.Flush()
}

同理除了使用NewWriter,还可以使用NewWriterSize

ioutil 写入文件

前面介绍ioutil.ReadFile可以读取整个文件,另外ioutil.WriterFile也可以一次性将内容写入文件。

语法如下:

plain
err := ioutil.WriterFile("xxx.txt", []byte(str), 0644)

如下:

go
package main

import (
	"fmt"
	"io/ioutil"
)

func main() {
	str := `
	融融的三月,万物尽苏醒

	蜿蜒曲折的小路承载着儿时的记忆

	鸟儿在树梢吟唱,歌颂着新春好光景

	阳光明媚,和着泥土和花香

	舒展手臂抱向天空,拥抱朵朵云彩

	大地又重新充满了生机。
	`
	err := ioutil.WriteFile("./c.txt", []byte(str), 0644)
	if err != nil {
		fmt.Printf("Write File Failed.err:%s\n", err)
		return
	}
}

日志库

需求

  • 支持往不同地方写日志
  • 日志分级别
    • Debug
    • Trace
    • Info
    • Warning
    • Error
    • Fatal
  • 日志支持开关控制
  • 日志记录包含时间、行号、文件名、日志级别、日志信息
  • 日志文件要切割
    • 按大小切割
    • 按时间切割
最近更新