☰
Go Web 编程实战:用 `os` 包完成文件与目录操作(基于 build-web-application-with-golang 第 7.5 节)
2026/10/4 7:29:45 网站建设 项目流程
  • 文档
  • 教程

【免费下载链接】build-web-application-with-golang

A golang ebook intro how to build a web with golang

项目地址:https://gitcode.com/gh_mirrors/bu/build-web-application-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") }

这段代码的执行过程值得仔细推敲:

  1. os.Mkdir("astaxie", 0777)先创建单层目录astaxie;
  2. os.MkdirAll("astaxie/test1/test2", 0777)在此基础上递归创建test1、test2两级子目录;
  3. 由于此时astaxie目录下已存在子目录,并非空目录,所以os.Remove("astaxie")会返回错误——这正是程序打印错误信息的原因;
  4. 最后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 行文本。这段代码有三个实战要点:

  1. 错误必须检查:os.Create失败(如目录不存在、权限不足)时立即打印并return,避免后续空指针操作;
  2. defer fout.Close()务必使用:Go 中文件对象需要显式关闭,defer保证函数退出时必然释放文件描述符;
  3. 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

项目地址:https://gitcode.com/gh_mirrors/bu/build-web-application-with-golang
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询