一、文件基础分类
1. 设备文件(标准输入 / 输出)
操作系统自带的默认打开设备文件,程序启动即可直接使用
- 标准输出设备 stdout :屏幕
fmt.Println()底层封装os.Stdout,向屏幕输出内容- 原生 API:
os.Stdout.WriteString("内容\n") - 可手动关闭:
os.Stdout.Close(),关闭后无法再打印输出
- 标准输入设备 stdin :键盘
fmt.Scan(&变量)从键盘读取用户输入- 底层对应
os.Stdin
2. 磁盘文件(存储在硬盘)
断电后数据持久保存,分为两类:
- 文本文件 :记事本打开不乱码,由字符组成(
.txt、.md、.json) - 二进制文件:记事本打开乱码,存储原始二进制数据(图片、视频、exe、压缩包)
补充:文件存在的意义
内存是临时存储,程序退出 / 设备断电后数据直接丢失;磁盘文件可永久保存数据。
二、os 包核心文件操作 API
1. 创建文件两种方式
go
Go
// 方式1:常用,根据文件名创建文件,权限0666,文件默认可读可写
func Create(name string) (*os.File, error)
// 方式2:通过文件描述符创建文件,底层底层接口,业务开发极少使用
func NewFile(fd uintptr, name string) *os.File
2. 打开文件两种方式
go
Go
// 方式1:只读模式打开文件,底层封装OpenFile
func Open(name string) (*os.File, error)
// 方式2:自定义打开模式、权限,功能最全(读写/追加/创建都靠它)
func OpenFile(name string, flag int, perm uint32) (*os.File, error)
flag:打开模式标识(只读、只写、读写、追加等)perm:文件权限(Linux 权限数字,如 0666)
3. 文件基础操作能力
文件 API 支持四大核心操作:创建、打开、读、写、删除
三、标准设备文件(Stdin/Stdout)代码示例
go
Go
package main
import (
"fmt"
"os"
)
func main() {
// 1. 标准输出打印(封装os.Stdout)
fmt.Println("are u ok?")
// 原生Stdout写入
os.Stdout.WriteString("are u ok?\n")
// 关闭标准输出,关闭后无法打印
// os.Stdout.Close()
// 2. 标准输入:键盘读取
var a int
fmt.Println("请输入a:")
fmt.Scan(&a)
fmt.Println("a = ", a)
}
四、磁盘文件写入操作 os.Create + WriteString
知识点
os.Create(path)文件不存在则新建,存在则清空原有内容- 文件打开后必须关闭,推荐
defer f.Close()延迟关闭,避免文件句柄泄漏 f.WriteString(string)写入字符串,返回写入字节长度与错误
go
Go
package main
import (
"fmt"
"os"
)
// 向文件循环写入内容
func WriteFile(path string) {
// 创建/清空文件
f, err := os.Create(path)
if err != nil {
fmt.Println("创建文件失败 err = ", err)
return
}
// 函数结束自动关闭文件
defer f.Close()
for i := 0; i < 10; i++ {
buf := fmt.Sprintf("i = %d\n", i)
n, err := f.WriteString(buf)
if err != nil {
fmt.Println("写入失败 err = ", err)
}
fmt.Printf("本次写入字节数:%d\n", n)
}
}
func main() {
path := "./demo.txt"
WriteFile(path)
}
五、磁盘文件读取操作 os.Open + Read
核心要点
os.Open()只读打开文件,不能写入Read([]byte):将文件数据读取到字节切片缓冲区- 返回值
n:实际读到的字节数量,打印时截取buf[:n],避免多余空字节 io.EOF:文件读取完毕标记,读到 EOF 代表文件读完
go
Go
package main
import (
"fmt"
"io"
"os"
)
func ReadFile(path string) {
// 只读打开文件
f, err := os.Open(path)
if err != nil {
fmt.Println("打开文件失败 err = ", err)
return
}
defer f.Close()
// 开辟2KB缓冲区
buf := make([]byte, 1024*2)
n, err1 := f.Read(buf)
// 排除正常结束的EOF错误
if err1 != nil && err1 != io.EOF {
fmt.Println("读取文件失败 err1 = ", err1)
return
}
// 只打印实际读到的数据
fmt.Println("文件内容:", string(buf[:n]))
}
func main() {
ReadFile("./demo.txt")
}
六、bufio 缓冲区:按行读取文件(大文件推荐)
作用
直接 Read 一次性读取全部内容,大文件占用内存高;bufio 提供缓冲区,支持按行读取,节省内存。
go
Go
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func ReadFileByLine(path string) {
f, err := os.Open(path)
if err != nil {
fmt.Println("打开失败 err = ", err)
return
}
defer f.Close()
// 创建带缓冲读取器
r := bufio.NewReader(f)
for {
// 按换行符分割读取一行,包含\n
lineBuf, err := r.ReadString('\n')
if err != nil {
// 读到文件末尾,跳出循环
if err == io.EOF {
break
}
fmt.Println("读取行失败 err = ", err)
return
}
fmt.Print(lineBuf)
}
}
七、实战案例:文件拷贝工具(命令行传参)
功能说明
- 通过
os.Args获取命令行执行参数 - 参数格式:
程序名 源文件路径 目标文件路径 - 开辟 4KB 缓冲区循环读写,适合任意大小文件
- 自动校验参数数量、源文件与目标文件不能同名
go
Go
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 获取命令行参数列表
args := os.Args
// 参数必须是:程序名 src dst 共3个
if len(args) != 3 {
fmt.Println("使用方式:go run main.go 源文件路径 目标文件路径")
return
}
srcFileName := args[1]
dstFileName := args[2]
if srcFileName == dstFileName {
fmt.Println("错误:源文件和目标文件不能相同!")
return
}
// 打开源文件(只读)
sF, err := os.Open(srcFileName)
if err != nil {
fmt.Println("打开源文件失败 err = ", err)
return
}
// 创建目标文件(清空原有内容)
dF, err := os.Create(dstFileName)
if err != nil {
fmt.Println("创建目标文件失败 err = ", err)
return
}
// 延迟关闭两个文件
defer sF.Close()
defer dF.Close()
// 4KB缓冲区循环读写
buf := make([]byte, 4*1024)
for {
// 读源文件
n, err := sF.Read(buf)
if err != nil {
if err == io.EOF {
// 文件读取完成,退出循环
break
}
fmt.Println("读取源文件出错 err = ", err)
return
}
// 读到多少,写入多少到目标文件
_, err = dF.Write(buf[:n])
if err != nil {
fmt.Println("写入目标文件出错 err = ", err)
return
}
}
fmt.Println("文件拷贝完成!")
}
八、高频易错点汇总(复习重点)
- 文件打开后必须关闭 ,优先使用
defer Close(),防止句柄泄露 os.Create()打开已有文件会清空内容;只读读取用os.Open()Read(buf)返回 n 为实际读取字节,输出必须截取buf[:n],否则会打印空占位字节- 文件读取报错要判断
err != io.EOF,读到末尾属于正常情况,不算错误 - 大文件不要一次性全部读取,使用
bufio按行读取,降低内存占用 os.Args第一个参数是程序自身名称,业务参数从下标 1、2 开始取- 标准输入输出设备无需手动 Open,程序启动自动打开
- 文本 / 二进制文件读写 API 无区分,底层全部操作字节切片
九、方案选型对比
表格
| 读取方式 | 适用场景 | 优缺点 |
|---|---|---|
file.Read() 一次性读 |
小文件 | 代码简单,大文件占用内存高 |
bufio.NewReader 按行读 |
日志、大文本文件 | 内存占用低,逐行处理,推荐业务使用 |
| 循环缓冲区读写(拷贝案例) | 图片、视频等二进制大文件 | 稳定通用,工业级文件复制方案 |
十、整体知识总结
- 文件分设备文件 (标准输入输出)、磁盘文件(文本 / 二进制);磁盘文件持久化存储数据
- 创建文件:
os.Create();只读打开:os.Open();自定义模式打开:os.OpenFile() - 写入:
WriteString();基础读取:Read([]byte);按行读取:bufio.Reader.ReadString() - 文件拷贝核心逻辑:开辟固定大小缓冲区,循环读源文件、写目标文件
- 开发规范:
defer延迟关闭文件、处理io.EOF正常结束标记、校验文件操作错误