Go语言_文件---文件操作

一、文件基础分类

1. 设备文件(标准输入 / 输出)

操作系统自带的默认打开设备文件,程序启动即可直接使用

  1. 标准输出设备 stdout :屏幕
    • fmt.Println() 底层封装 os.Stdout,向屏幕输出内容
    • 原生 API:os.Stdout.WriteString("内容\n")
    • 可手动关闭:os.Stdout.Close(),关闭后无法再打印输出
  2. 标准输入设备 stdin :键盘
    • fmt.Scan(&变量) 从键盘读取用户输入
    • 底层对应 os.Stdin

2. 磁盘文件(存储在硬盘)

断电后数据持久保存,分为两类:

  1. 文本文件 :记事本打开不乱码,由字符组成(.txt.md.json
  2. 二进制文件:记事本打开乱码,存储原始二进制数据(图片、视频、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

知识点

  1. os.Create(path) 文件不存在则新建,存在则清空原有内容
  2. 文件打开后必须关闭,推荐 defer f.Close() 延迟关闭,避免文件句柄泄漏
  3. 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

核心要点

  1. os.Open() 只读打开文件,不能写入
  2. Read([]byte):将文件数据读取到字节切片缓冲区
  3. 返回值 n:实际读到的字节数量,打印时截取 buf[:n],避免多余空字节
  4. 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)
	}
}

七、实战案例:文件拷贝工具(命令行传参)

功能说明

  1. 通过 os.Args 获取命令行执行参数
  2. 参数格式:程序名 源文件路径 目标文件路径
  3. 开辟 4KB 缓冲区循环读写,适合任意大小文件
  4. 自动校验参数数量、源文件与目标文件不能同名

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

八、高频易错点汇总(复习重点)

  1. 文件打开后必须关闭 ,优先使用 defer Close(),防止句柄泄露
  2. os.Create() 打开已有文件会清空内容;只读读取用 os.Open()
  3. Read(buf) 返回 n 为实际读取字节,输出必须截取 buf[:n],否则会打印空占位字节
  4. 文件读取报错要判断 err != io.EOF,读到末尾属于正常情况,不算错误
  5. 大文件不要一次性全部读取,使用 bufio 按行读取,降低内存占用
  6. os.Args 第一个参数是程序自身名称,业务参数从下标 1、2 开始取
  7. 标准输入输出设备无需手动 Open,程序启动自动打开
  8. 文本 / 二进制文件读写 API 无区分,底层全部操作字节切片

九、方案选型对比

表格

读取方式 适用场景 优缺点
file.Read() 一次性读 小文件 代码简单,大文件占用内存高
bufio.NewReader 按行读 日志、大文本文件 内存占用低,逐行处理,推荐业务使用
循环缓冲区读写(拷贝案例) 图片、视频等二进制大文件 稳定通用,工业级文件复制方案

十、整体知识总结

  1. 文件分设备文件 (标准输入输出)、磁盘文件(文本 / 二进制);磁盘文件持久化存储数据
  2. 创建文件:os.Create();只读打开:os.Open();自定义模式打开:os.OpenFile()
  3. 写入:WriteString();基础读取:Read([]byte);按行读取:bufio.Reader.ReadString()
  4. 文件拷贝核心逻辑:开辟固定大小缓冲区,循环读源文件、写目标文件
  5. 开发规范:defer 延迟关闭文件、处理 io.EOF 正常结束标记、校验文件操作错误
相关推荐
稚南城才子,乌衣巷风流16 小时前
函数:编程中的核心概念
开发语言·前端·javascript
阿米亚波16 小时前
【C++】流式数据输入处理(不完全整理)
开发语言·c++·笔记
大模型码小白16 小时前
JAVA 集合框架进阶:List 与 Set 的深度解析与实战
java·开发语言·人工智能·windows·语言模型·list·ai编程
IT_陈寒16 小时前
为什么我的JavaScript异步代码总是不按顺序执行?
前端·人工智能·后端
星栈17 小时前
Node 框架怎么选?Express、Koa、Egg、NestJS 场景化选型指南
后端·node.js
名字还没想好☜17 小时前
Go 的 time.Ticker 陷阱:定时任务里被忽略的内存泄漏与正确关闭
java·数据库·golang·go·定时器
锋行天下17 小时前
打造企业内部知识库系统RAG全栈项目
前端·后端·架构
皓月斯语17 小时前
【C++基础】三目运算符
开发语言·数据结构·c++
初願致夕霞18 小时前
C++懒汉单例设计详解
服务器·开发语言·c++
脱胎换骨-军哥18 小时前
C++分布式系统设计:从通信引擎到分布式共识
开发语言·c++·分布式