- 文档
- 教程
【免费下载链接】build-web-application-with-golang
A golang ebook intro how to build a web with golang
文件是每一台计算机上的基本对象,Web 应用同样离不开文件读写——无论是生成目录、上传文件、写日志还是解析数据。本篇指南以开源电子书《build-web-application-with-golang》(Go Web 编程)第 7 章「文本处理」的 7.5 节为核心,系统讲解 Go 标准库os包中目录与文件操作的全部核心函数:Mkdir、MkdirAll、Remove、RemoveAll、Create、Open、OpenFile、Write、WriteAt、WriteString、Read、ReadAt。读完本文,你将掌握在 Go Web 应用中创建目录、读写文件、删除文件以及处理文件上传落盘的完整实战能力。
本文对应的原始章节为 es/07.5.md(西班牙语版)与 en/07.5.md(英文版),属于全书第 7 章 文本处理 的一部分。全文代码基于 Go 标准库
os包,可在任意 Go 版本中直接运行验证。
目录操作:创建、递归创建与删除
在 Go 中,绝大多数文件操作函数都位于标准库os包中。目录相关的核心函数共有四个,覆盖了「创建单层目录、递归创建多层目录、删除单层目录、递归删除整棵目录树」四种场景:
| 函数签名 | 功能说明 |
|---|---|
func Mkdir(name string, perm FileMode) error | 创建名称为name的单层目录,权限由perm指定,例如0777。 |
func MkdirAll(path string, perm FileMode) error | 根据path递归创建多级子目录,例如astaxie/test1/test2,中间缺失的层级会一并创建。 |
func Remove(name string) error | 删除名称为name的目录;如果该路径不是目录或目录非空,会返回错误。 |
func RemoveAll(path string) error | 根据path递归删除多级目录及其下所有内容;如果path是单个名称,则连同该目录下的所有子目录一并删除。 |
原文给出了一个完整的演示程序,创建与删除目录的完整流程如下:
package main import ( "fmt" "os" ) func main() { os.Mkdir("astaxie", 0777) os.MkdirAll("astaxie/test1/test2", 0777) err := os.Remove("astaxie") if err != nil { fmt.Println(err) } os.RemoveAll("astaxie") }这段代码的执行过程值得仔细推敲:
os.Mkdir("astaxie", 0777)先创建单层目录astaxie;os.MkdirAll("astaxie/test1/test2", 0777)在此基础上递归创建test1、test2两级子目录;- 由于此时
astaxie目录下已存在子目录,并非空目录,所以os.Remove("astaxie")会返回错误——这正是程序打印错误信息的原因; - 最后
os.RemoveAll("astaxie")递归删除整个目录树,错误得以消除。
权限参数说明:perm的类型是FileMode,0777表示文件所有者、所属组和其他用户均拥有读(4)、写(2)、执行(1)权限。Web 应用中创建上传目录、日志目录时,通常配合0666(文件读写)或0755(目录读写执行)使用。
创建与打开文件:Create、NewFile、Open 与 OpenFile
新建文件有两种方式:
| 函数签名 | 功能说明 |
|---|---|
func Create(name string) (file *File, err Error) | 根据提供的文件名创建新文件,返回可读写的文件对象,默认权限为0666。 |
func NewFile(fd uintptr, name string) *File | 根据底层文件描述符(file descriptor)创建文件对象并返回。 |
打开文件同样有两种方式:
| 函数签名 | 功能说明 |
|---|---|
func Open(name string) (file *File, err Error) | 以只读方式打开名为name的文件,其内部实现实际上调用了OpenFile。 |
func OpenFile(name string, flag int, perm uint32) (file *File, err Error) | 以指定模式打开名为name的文件。flag是打开方式(只读、读写等),perm是文件权限。 |
OpenFile是最底层的打开函数,flag常用取值包括:
os.O_RDONLY:只读;os.O_WRONLY:只写;os.O_RDWR:读写;os.O_CREATE:文件不存在时创建;os.O_TRUNC:打开时清空文件内容;os.O_APPEND:以追加方式写入。
多个标志可用|按位组合,例如os.O_WRONLY|os.O_CREATE|os.O_TRUNC表示「只写、不存在则创建、创建后清空」。
源码佐证:这种组合方式正是本书 4.5 节文件上传示例 中保存上传文件的实际写法。在该示例的saveUpload函数里,接收端拿到multipart.File后,用os.OpenFile(localFilename, os.O_WRONLY|os.O_CREATE, 0666)创建本地文件,随后用io.Copy(f, file)将上传内容流式写入磁盘。可见flag决定读写意图、perm决定新文件权限,二者缺一不可:
f, err := os.OpenFile(localFilename, os.O_WRONLY|os.O_CREATE, 0666) checkError(err) defer f.Close() _, err = io.Copy(f, file) checkError(err)写入文件:Write、WriteAt 与 WriteString
os.File对象提供三个写入方法:
| 方法签名 | 功能说明 |
|---|---|
func (file *File) Write(b []byte) (n int, err Error) | 向文件写入byte类型(二进制)内容,返回实际写入的字节数n。 |
func (file *File) WriteAt(b []byte, off int64) (n int, err Error) | 从文件中指定位置off开始写入byte类型内容。 |
func (file *File) WriteString(s string) (ret int, err Error) | 向文件写入字符串内容。 |
原文的写入示例演示了WriteString与Write混用的典型写法,并借助defer保证文件关闭:
package main import ( "fmt" "os" ) func main() { userFile := "astaxie.txt" fout, err := os.Create(userFile) if err != nil { fmt.Println(userFile, err) return } defer fout.Close() for i := 0; i < 10; i++ { fout.WriteString("Just a test!\r\n") fout.Write([]byte("Just a test!\r\n")) } }执行后,astaxie.txt中将写入 20 行文本。这段代码有三个实战要点:
- 错误必须检查:
os.Create失败(如目录不存在、权限不足)时立即打印并return,避免后续空指针操作; defer fout.Close()务必使用:Go 中文件对象需要显式关闭,defer保证函数退出时必然释放文件描述符;WriteString与Write的本质区别:前者接收字符串,后者接收[]byte。二者内部最终都落到系统调用write,只是入参类型不同,[]byte写法在需要写入二进制数据(如图片、序列化结果)时更通用。
读取文件:Read 与 ReadAt
读取文件对应两个方法:
| 方法签名 | 功能说明 |
|---|---|
func (file *File) Read(b []byte) (n int, err Error) | 从文件当前位置读取数据填充到缓冲区b,返回读取字节数。 |
func (file *File) ReadAt(b []byte, off int64) (n int, err Error) | 从文件中指定位置off开始读取数据到b,不改变文件指针位置。 |
原文的读取示例演示了「固定缓冲区 + 循环读取」的经典模式:
package main import ( "fmt" "os" ) func main() { userFile := "asatxie.txt" fl, err := os.Open(userFile) if err != nil { fmt.Println(userFile, err) return } defer fl.Close() buf := make([]byte, 1024) for { n, _ := fl.Read(buf) if 0 == n { break } os.Stdout.Write(buf[:n]) } }关键逻辑在于循环体:每次调用fl.Read(buf)至多填充 1024 字节,返回实际读取字节数n;当读到文件末尾时n == 0,循环终止;每次读取到的内容通过os.Stdout.Write(buf[:n])直接输出到标准输出,实现整文件内容的逐块打印。注意buf[:n]的切片写法——只写出本次实际读入的部分,避免把缓冲区残留内容一并输出。该模式是 Web 应用中流式读取大文件(如日志分析、文件下载)的通用基础。
删除文件:Remove
Go 语言中删除文件和删除目录使用同一个函数:
| 函数签名 | 功能说明 |
|---|---|
func Remove(name string) error | 删除名称为name的文件或目录。当name以/结尾时,表示删除的是目录;若目录非空,删除会返回错误。 |
需要递归删除目录树时,改用前文介绍过的os.RemoveAll(path string)。
与 Web 应用实战的结合
文件操作在 Web 编程中高频出现:生成日志目录、保存用户上传、缓存静态资源、读取模板文件等。本书 4.5 节的上传示例 完整串联了本节的知识点——os.OpenFile以os.O_WRONLY|os.O_CREATE模式创建落盘文件,权限0666,配合defer f.Close()与io.Copy完成流式写入。这正是本节「创建文件 → 写入文件 → 关闭文件」三步流程在真实 Web 场景中的直接应用。
实践提示:仓库 en/code/readme.md 中说明,若要独立运行各章节示例代码,可将环境变量GOPATH设置为code目录路径,以避免工作区路径问题;本文所有示例均为独立main包,直接go run即可验证。
小结
本节围绕os包梳理了 Go 文件操作的最小闭环:用Mkdir/MkdirAll建目录,用Create/Open/OpenFile建文件与打开文件,用Write/WriteAt/WriteString写入,用Read/ReadAt读取,用Remove/RemoveAll清理。配合「检查错误、defer关闭、缓冲区循环读取」三个习惯,足以覆盖绝大多数 Web 应用的文件处理需求。
延伸阅读
- 本章总览:7 文本处理
- 上一节:模板处理(第 7 章 MVC 视图层与
template包) - 下一节:字符串处理(
strings包常用操作) - 全书目录:preface.md
- 文档
- 教程
【免费下载链接】build-web-application-with-golang
A golang ebook intro how to build a web with golang
相关推荐
Go Web 文件操作实战精讲:深入 os 包掌握目录与文件读写(《Build Web Application with Golang》7.5 节)
Go Web 文件操作实战精讲:深入 os 包掌握目录与文件读写(《Build Web Application with Golang》7.5 节) 文件操作是
文档教程Hydra Multi-run 参数扫描实战:从 `-m` 标志到 Sweeper/Launcher 插件体系
Hydra Multi run 参数扫描实战:从 m 标志到 Sweeper/Launcher 插件体系 导读 多运行(Multi run)是 Hydra 框架
文档教程Go 标准库 XML 编解码实战:基于 build-web-application-with-golang 第 7.1 节
Go 标准库 XML 编解码实战:基于 build web application with golang 第 7.1 节 导读 XML 是 Web 服务中最常
文档教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考