Go语言文件读写与拷贝:从基础流操作到实战案例
本文深入解析Go语言中的文件IO操作,涵盖读取、写入(含覆盖与追加)以及文件拷贝的完整实现方案。重点讲解os.Open、ioutil.ReadFile、os.OpenFile及io.Copy的标准用法,提供可复用的路径判断函数,帮助开发者掌握高效的文件处理逻辑。
文件与流的基础概念
在Go语言程序中,文件作为数据的存储介质,是通过“流”的形式进行交互的。理解输入流和输出流的定义是进行操作的前提:
- 输入流:数据从文件传输到内存的路径。
- 输出流:数据从内存传输到文件的路径。
os.File结构体封装了所有文件相关的操作,在实际开发中,我们需要关注的是如何正确地打开、关闭以及通过缓冲机制高效地读写数据。
文件的读取操作
第1步:逐行读取文本
适用于大文件或需要流式处理的场景,使用bufio.NewReader可以避免一次性将大文件载入内存导致的内存泄漏或性能问题。
操作要点:
- 入口:
os.Open打开文件路径。 - 动作:创建
bufio.Reader,循环调用ReadString('\n')。 - 完成状态:检测到
io.EOF时跳出循环。
注意编码问题:若文件为GBK等非标UTF-8编码,需引入转码库(如mahonia)或使用标准库处理,以防控制台中文乱码。
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
// 1. 打开文件
file, err := os.Open("F:/test.txt")
if err != nil {
fmt.Println("open file err=", err)
return
}
// 2. 确保关闭文件,防止内存泄漏
defer file.Close()
// 3. 创建带缓存的Reader
reader := bufio.NewReader(file)
for {
str, err := reader.ReadString('\n')
fmt.Print(str) // 若需转码此处应加入逻辑
/*
你好啊
真的很好asdb
*/
if err == io.EOF { // 4. 到达文件末尾
break
}
}
}第2步:一次性读取小文件
对于较小的配置文件或文本,可直接使用ioutil.ReadFile,它会自动处理打开和关闭文件的操作,代码更简洁。
// 一次性读取所有内容为字节切片
content, err := ioutil.ReadFile("f:/test.txt")
if err != nil {
fmt.Println("read file err=", err)
}
fmt.Print(string(content))
文件的写入与修改操作
Go语言提供了统一的os.OpenFile函数,通过组合不同的flag参数,可以灵活实现创建、覆盖、追加等不同写入需求。
第1步:创建新文件并写入
使用 os.O_CREATE | os.O_WRONLY 标志。若文件已存在,不会清空原有内容,而是继续向后写(类似追加)。为确保是新文件,通常配合检查逻辑。
filename := "f:/test2.txt"
file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
fmt.Println("open file err=", err)
return
}
defer file.Close()
writer := bufio.NewWriter(file)
for i := 0; i < 5; i++ {
writer.WriteString("hello,Gardon\r\n")
}
writer.Flush() // 重要:刷新缓冲区确保数据落盘
第2步:覆盖已有文件内容
使用 os.O_TRUNC 标志。这会将原文件长度截断为0,然后再写入新数据。
file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return
}
defer file.Close()
writer := bufio.NewWriter(file)
for i := 0; i < 10; i++ {
writer.WriteString("你好,世界!!\r\n")
}
writer.Flush()
第3步:向已有文件末尾追加内容
使用 os.O_APPEND 标志,数据会追加到文件末尾而不清空原内容。
file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
return
}
defer file.Close()
writer := bufio.NewWriter(file)
writer.WriteString("ABC! ENGLISH!\r\n")
writer.Flush()
第4步:混合读写操作
若需先读取再追加,可使用 os.O_RDWR | os.O_APPEND 标志,同时具备读和写权限。
常用文件操作案例
判断文件或目录是否存在
在进行文件操作前,检查路径是否存在是一个良好的编程习惯。可以通过 os.Stat 返回的错误类型来判断。
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil // 文件/目录存在
}
if os.IsNotExist(err) {
return false, nil // 明确不存在
}
// 其他错误(如权限不足),返回错误
return false, err
}
拷贝文件
Go语言标准库 io 提供了 io.Copy 方法,可以在两个实现了 Reader 和 Writer 接口的对象之间进行高效的数据拷贝。相比手动循环读取写入,这是最推荐的方式。
操作步骤:
- 准备源文件:以只读模式
os.Open打开源文件。 - 准备目标文件:根据文件是否存在,决定使用
O_CREATE(不存在则创建)还是O_WRONLY|O_TRUNC(存在则清空后写入)。 - 执行拷贝:调用
io.Copy(writer, reader)。
func CopyFile(writerFileName string, readerFileName string) (written int64, err error) {
// 1. 打开源文件
ReaderFile, err2 := os.Open(readerFileName)
if err2 != nil {
return 0, err2
}
defer ReaderFile.Close()
reader := bufio.NewReader(ReaderFile)
// 2. 确定目标文件操作模式
WriterFlag, _ := PathExists(writerFileName)
var WriterFile *os.File
var err error
if WriterFlag {
// 已存在,清空后覆盖
WriterFile, err = os.OpenFile(writerFileName, os.O_WRONLY|os.O_TRUNC, 0666)
} else {
// 不存在,新建文件
WriterFile, err = os.OpenFile(writerFileName, os.O_WRONLY|os.O_CREATE, 0666)
}
if err != nil {
return 0, err
}
defer WriterFile.Close()
writer := bufio.NewWriter(WriterFile)
// 3. 执行高效拷贝
return io.Copy(writer, reader)
}以上就是Go语言文件读写操作的详细内容,更多关于Go语言文件读写操作的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













