go语言
包
文件操作
🔹 os.Args
-
获取命令行参数
获取命令行参数
os.Args []string
📌 说明
- os.Args 是一个字符串切片([]string)
- 第一个元素 os.Args[0] 是程序本身路径
- 后续元素为传入参数
📦 常用操作
-
获取参数个数
-
示例
fmt.Println(len(os.Args))
-
遍历参数
-
示例
for i, v := range os.Args { fmt.Println(i, v) }
-
获取指定参数
-
示例
if len(os.Args) > 1 { fmt.Println(os.Args[1]) }
🧪 综合示例
fmt.Println(“程序路径:”, os.Args[0])
if len(os.Args) > 1 { fmt.Println(“参数:”, os.Args[1:]) }
-
修改当前工作目录
改变当前进程的工作目录
.Chdir(dir string) error -
说明:
-
成功后调用 os.Getwd() 会返回新的当前目录。
-
若目录不存在或没有权限会返回错误。
-
在并发程序中要小心:Chdir 改变的是进程全局状态,可能影响其他 goroutine 的文件操作。
-
示例
package main
import (
"fmt"
"os"
)
func main() {
// 切换到 /tmp
if err := os.Chdir("/tmp"); err != nil {
fmt.Println("切换失败:", err)
return
}
wd, _ := os.Getwd()
fmt.Println("当前目录:", wd)
// 相对路径示例:在新工作目录下创建文件
f, err := os.Create("demo.txt")
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
defer f.Close()
f.WriteString("hello")
}
-
修改文件权限(按路径)
通过文件路径设置权限位
.Chmod(name string, mode os.FileMode) error -
说明:
-
在 Unix 系统上以常见的八进制权限表示法设置。
-
在 Windows 上支持有限(某些权限位会被忽略或映射)。
-
只有文件所有者或具有适当权限的用户才能成功修改权限。
-
示例(按路径)
if err := os.Chmod("test.txt", 0644); err != nil {
fmt.Println("修改权限失败:", err)
}
-
方法形式(通过 *os.File)
与 os.Chmod 等价,但通过已打开的文件对象操作
(*os.File).Chmod(mode os.FileMode) error -
示例(通过文件对象)
f, _ := os.OpenFile("test.txt", os.O_RDWR, 0)
defer f.Close()
if err := f.Chmod(0755); err != nil {
fmt.Println("f.Chmod 失败:", err)
}
-
修改文件所有者(按路径)
修改文件属主和属组(Unix 专用)
.Chown(name string, uid, gid int) error -
说明:
-
uid/gid 使用操作系统的用户/组 ID(整数)。
-
需要有相应权限(通常要求 root)才能为其他用户更改所有者。
-
若只想修改属主或属组之一,可将另一个参数设为 -1(在一些平台支持,以保持原值;具体以平台文档为准)。
-
示例(按路径)
if err := os.Chown("data.txt", 1001, 1001); err != nil {
fmt.Println("Chown 失败:", err)
}
-
方法形式(通过 *os.File)
通过已打开的文件描述符修改属主/属组
(*os.File).Chown(uid, gid int) error -
示例(通过文件对象)
f, _ := os.Open("data.txt")
defer f.Close()
if err := f.Chown(1001, 1001); err != nil {
fmt.Println("f.Chown 失败:", err)
}
-
注意事项
-
在容器或受限环境(如某些 CI)中可能无法成功更改所有者。
-
对于跨平台程序,应在运行时检测操作系统并提供回退逻辑或报错提示。
-
修改访问/修改时间
设置文件的访问时间和修改时间
.Chtimes(name string, atime time.Time, mtime time.Time) error -
说明:
-
atime:最后访问时间(access time)。
-
mtime:最后修改时间(modification time)。
-
有些文件系统或挂载选项可能忽略 atime 更新(例如 noatime)。
-
需要对文件有写权限或合适的权限以修改时间戳。
-
示例
package main
import (
"fmt"
"os"
"time"
)
func main() {
// 将文件的访问/修改时间都设置为 2020-01-01 00:00:00
t := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
if err := os.Chtimes("test.txt", t, t); err != nil {
fmt.Println("Chtimes 失败:", err)
return
}
fmt.Println("时间戳已更新")
}
-
额外示例:组合使用(切换目录并修改文件属性)
-
综合示例展示 Chdir -> OpenFile -> Chmod -> Chtimes -> Close 的流程
-
示例
package main
import (
"fmt"
"os"
"time"
)
func main() {
// 切换到目标目录
if err := os.Chdir("/tmp/myapp"); err != nil {
fmt.Println("Chdir 失败:", err)
return
}
// 打开或创建文件
f, err := os.OpenFile("log.txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("OpenFile 失败:", err)
return
}
defer f.Close()
// 修改权限
if err := f.Chmod(0640); err != nil {
fmt.Println("Chmod 失败:", err)
}
// 写入并同步
if _, err := f.WriteString("entry\n"); err == nil {
f.Sync()
}
// 更新时间戳为现在
now := time.Now()
if err := os.Chtimes("log.txt", now, now); err != nil {
fmt.Println("Chtimes 失败:", err)
}
// 如果需要,尝试修改属主(仅 Unix 且需要权限)
if err := f.Chown(1001, 1001); err != nil {
// 若没有权限,记录但不终止程序
fmt.Println("Chown 失败(可能需要 root):", err)
}
fmt.Println("操作完成")
}
-
小结与注意点
-
os.Chdir 会改变进程全局状态,在并发程序中慎用;优先使用绝对路径避免切换目录带来的副作用。
-
os.Chmod/os.Chtimes 可以通过路径或已打开的 *os.File 方法调用,注意权限与平台差异(Windows 与 Unix 行为不同)。
-
os.Chown 仅在类 Unix 系统上有实际效果,且通常需要更高权限(root)。在跨平台工具中应检测运行时 OS 并提供相应提示或回退措施。
-
所有系统调用返回错误都需要检查并合理处理(记录/回退/提示用户),以保证程序健壮性。
-
清空环境变量
清空当前进程的所有环境变量
os.Clearenv() -
说明:
-
调用后,所有通过 os.Getenv 获取的环境变量都会失效
-
常用于安全场景(避免敏感信息泄露)
-
操作是全局性的,会影响整个进程
-
示例
os.Setenv("TEST", "123")
fmt.Println(os.Getenv("TEST")) // 123
os.Clearenv()
fmt.Println(os.Getenv("TEST")) // 空
-
复制文件系统内容(Go1.21+)
将 fs.FS 文件系统中的内容复制到本地目录
os.CopyFS(dir string, fsys fs.FS) error -
说明:
-
常用于 embed 文件系统导出到磁盘
-
dir 是目标目录
-
fsys 是源文件系统(如 embed.FS)
-
示例
// 假设已有 embed.FS
err := os.CopyFS("./output", myFS)
if err != nil {
fmt.Println("复制失败:", err)
}
-
创建文件
创建文件,如果文件存在会清空
os.Create(name string) (*os.File, error) -
说明:
-
等价于:
os.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
-
常用于快速写文件
-
实例化返回类型1
-
写入内容
-
.Write([]byte) (int, error)
-
示例
f, _ := os.Create(“a.txt”) defer f.Close() f.Write([]byte(“hello”))
-
写入字符串
-
.WriteString(string) (int, error)
-
示例
f.WriteString(“hello”)
-
关闭文件
-
.Close() error
-
示例
defer f.Close()
-
创建临时文件
在指定目录创建一个唯一的临时文件
os.CreateTemp(dir, pattern string) (*os.File, error) -
说明:
-
dir 为空时使用系统临时目录
-
pattern 支持通配符
* -
返回的文件名是唯一的,避免冲突
-
常用于缓存、测试、临时数据
-
实例化返回类型1
-
获取文件名
-
.Name() string
-
示例
f, _ := os.CreateTemp(“”, “tmp_*.txt”) fmt.Println(f.Name())
-
写入内容
-
.Write([]byte) (int, error)
-
示例
f.Write([]byte(“temp data”))
-
删除文件
-
os.Remove(name string) error
-
示例
os.Remove(f.Name())
-
关闭文件
-
.Close() error
-
示例
defer f.Close()
- 示例
f, err := os.CreateTemp("", "demo_*.txt")
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
defer os.Remove(f.Name()) // 用完删除
f.WriteString("临时文件")
fmt.Println("文件:", f.Name())
-
小结
-
os.Clearenv 👉 清空环境变量(全局影响)
-
os.CopyFS 👉 拷贝文件系统(常用于 embed)
-
os.Create 👉 创建文件(覆盖写)
-
os.CreateTemp 👉 创建唯一临时文件(安全推荐)
-
空设备文件
表示操作系统的空设备
os.DevNull -
说明:
-
在 Unix 系统中通常是 /dev/null
-
在 Windows 中为 NUL
-
常用于丢弃输出或测试
-
示例
f, _ := os.OpenFile(os.DevNull, os.O_WRONLY, 0)
defer f.Close()
f.Write([]byte("这段数据会被丢弃"))
-
目录项接口
表示目录中的一个条目
os.DirEntry -
说明:
-
常用于 os.ReadDir 返回结果
-
比 os.FileInfo 更高效(延迟获取信息)
-
常用方法
-
.Name() string
-
.IsDir() bool
-
.Type() fs.FileMode
-
.Info() (os.FileInfo, error)
-
示例
entries, _ := os.ReadDir(".")
for _, e := range entries {
fmt.Println(e.Name(), e.IsDir())
}
-
目录文件系统
将本地目录转换为 fs.FS 文件系统接口
os.DirFS(dir string) fs.FS -
说明:
-
常用于与 io/fs 生态配合
-
可用于 embed、http、template 等场景
-
示例
fsys := os.DirFS("./static")
data, _ := fs.ReadFile(fsys, "index.html")
fmt.Println(string(data))
-
获取环境变量列表
获取当前进程的所有环境变量
os.Environ() []string -
说明:
-
返回格式为:KEY=value
-
返回的是字符串切片
-
示例
envs := os.Environ()
for _, e := range envs {
fmt.Println(e)
}
-
小结
-
os.DevNull 👉 空设备(丢弃数据)
-
os.DirEntry 👉 目录项接口(ReadDir使用)
-
os.DirFS 👉 将目录转为文件系统接口
-
os.Environ 👉 获取全部环境变量
- 文件/系统错误(errors)
表示文件或资源已关闭
os.ErrClosed
-
说明:
-
对已关闭的文件执行读写操作时返回该错误
-
常见于 file.Close() 之后继续操作
-
示例
f, _ := os.Create("a.txt")
f.Close()
_, err := f.Write([]byte("test"))
if err == os.ErrClosed {
fmt.Println("文件已关闭")
}
表示操作超时
os.ErrDeadlineExceeded
-
说明:
-
常用于网络/IO操作(如 SetDeadline)
-
属于超时错误
-
示例
if err == os.ErrDeadlineExceeded {
fmt.Println("操作超时")
}
表示文件或目录已存在
os.ErrExist
-
说明:
-
常见于创建文件/目录时冲突
-
示例
_, err := os.OpenFile("a.txt", os.O_CREATE|os.O_EXCL, 0644)
if err == os.ErrExist {
fmt.Println("文件已存在")
}
表示无效参数或操作
os.ErrInvalid
-
说明:
-
传入非法参数时返回
-
示例
if err == os.ErrInvalid {
fmt.Println("无效参数")
}
表示对象不支持设置 deadline
os.ErrNoDeadline
-
说明:
-
对不支持 deadline 的文件调用 SetDeadline 时返回
-
示例
if err == os.ErrNoDeadline {
fmt.Println("不支持 deadline")
}
表示没有可用句柄(主要用于 Windows)
os.ErrNoHandle
-
说明:
-
Windows 特有错误
-
示例
if err == os.ErrNoHandle {
fmt.Println("无效句柄")
}
表示文件或目录不存在
os.ErrNotExist
-
说明:
-
常见于访问不存在文件
-
示例
_, err := os.Open("no.txt")
if err == os.ErrNotExist {
fmt.Println("文件不存在")
}
表示权限不足
os.ErrPermission
-
说明:
-
没有访问权限时返回
-
示例
_, err := os.Open("/root/secret")
if err == os.ErrPermission {
fmt.Println("权限不足")
}
表示进程已经结束
os.ErrProcessDone
-
说明:
-
用于 os.Process 相关操作
-
示例
if err == os.ErrProcessDone {
fmt.Println("进程已结束")
}
-
小结
-
ErrClosed 👉 资源已关闭
-
ErrDeadlineExceeded 👉 超时
-
ErrExist 👉 已存在
-
ErrInvalid 👉 无效参数
-
ErrNoDeadline 👉 不支持超时
-
ErrNoHandle 👉 无句柄(Windows)
-
ErrNotExist 👉 不存在
-
ErrPermission 👉 权限不足
-
ErrProcessDone 👉 进程结束
-
获取当前程序路径
返回当前可执行程序的路径
os.Executable() (string, error) -
说明:
-
返回的是已编译程序的路径(不是源码路径)
-
在不同系统下返回结果可能不同(符号链接等情况)
-
常用于获取程序目录、配置路径等
-
示例
path, err := os.Executable()
if err != nil {
fmt.Println("获取失败:", err)
return
}
fmt.Println("程序路径:", path)
-
退出程序
立即终止程序,并返回状态码
os.Exit(code int) -
说明:
-
code = 0 表示正常退出
-
非 0 表示异常退出
-
⚠️ 不会执行 defer(重要)
-
示例
if err != nil {
fmt.Println("发生错误")
os.Exit(1)
}
-
字符串变量展开(自定义规则)
根据自定义函数替换字符串中的变量
os.Expand(s string, mapping func(string) string) string -
说明:
-
变量格式:$var 或 ${var}
-
mapping 函数决定变量替换内容
-
灵活性高(可自定义变量来源)
-
示例
s := "Hello $name"
result := os.Expand(s, func(key string) string {
if key == "name" {
return "Go"
}
return ""
})
fmt.Println(result) // Hello Go
-
字符串环境变量展开
将字符串中的环境变量替换为实际值
os.ExpandEnv(s string) string -
说明:
-
基于当前环境变量(os.Getenv)
-
支持 $var 和 ${var}
-
示例
os.Setenv("USER", "gopher")
s := "Hello $USER"
result := os.ExpandEnv(s)
fmt.Println(result) // Hello gopher
-
小结
-
os.Executable 👉 获取程序路径
-
os.Exit 👉 立即退出程序(不会执行 defer)
-
os.Expand 👉 自定义变量替换
-
os.ExpandEnv 👉 环境变量替换
-
os.File
-
类型说明
-
os.File 表示一个已打开的文件或设备,是对底层文件描述符的封装。
-
常用于读写、获取元信息、改变权限、截断、同步等操作。
-
实现了多个标准接口(io.Reader、io.Writer、io.Seeker、io.Closer 等)。
-
常用方法(局部列举)
-
.Name() string
-
.Fd() uintptr
-
.Read(b []byte) (int, error)
-
.ReadAt(b []byte, off int64) (int, error)
-
.Write(b []byte) (int, error)
-
.WriteAt(b []byte, off int64) (int, error)
-
.WriteString(s string) (int, error)
-
.Seek(offset int64, whence int) (int64, error)
-
.Stat() (os.FileInfo, error)
-
.Chmod(mode os.FileMode) error
-
.Chown(uid, gid int) error
-
.Sync() error
-
.Truncate(size int64) error
-
.Readdir(n int) ([]os.FileInfo, error) // 当 File 为目录时
-
.Readdirnames(n int) ([]string, error) // 当 File 为目录时
-
.Close() error
-
完整示例(创建 - 写入 - Seek - 读取 - Stat - Truncate - Close)
package main
import (
"fmt"
"os"
"io"
)
func main() {
// 以读写模式创建/打开文件(0644 权限)
f, err := os.OpenFile("example.txt", os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
if err != nil {
fmt.Println("OpenFile failed:", err)
return
}
// 确保退出时关闭文件
defer func() {
if err := f.Close(); err != nil {
fmt.Println("Close failed:", err)
}
}()
// 写入字符串
if _, err := f.WriteString("Hello, Go File!\n"); err != nil {
fmt.Println("WriteString failed:", err)
return
}
// 同步到磁盘
if err := f.Sync(); err != nil {
fmt.Println("Sync failed:", err)
}
// 获取并打印文件描述符
fmt.Println("file descriptor:", f.Fd())
// Seek 到文件开头并读取内容
if _, err := f.Seek(0, io.SeekStart); err != nil {
fmt.Println("Seek failed:", err)
return
}
buf := make([]byte, 64)
n, err := f.Read(buf)
if err != nil && err != io.EOF {
fmt.Println("Read failed:", err)
return
}
fmt.Printf("read %d bytes: %q\n", n, string(buf[:n]))
// 获取文件信息
info, err := f.Stat()
if err != nil {
fmt.Println("Stat failed:", err)
return
}
fmt.Printf("name=%s size=%d mode=%s modtime=%v isdir=%v\n",
info.Name(), info.Size(), info.Mode().String(), info.ModTime(), info.IsDir())
// 截断文件(保留前 5 字节)
if err := f.Truncate(5); err != nil {
fmt.Println("Truncate failed:", err)
} else {
fmt.Println("Truncate succeeded")
}
// 再次读取(演示 ReadAt)
if _, err := f.Seek(0, io.SeekStart); err == nil {
buf2 := make([]byte, 20)
m, _ := f.ReadAt(buf2, 0)
fmt.Printf("after truncate read %d bytes: %q\n", m, string(buf2[:m]))
}
}
-
运行后会在当前目录生成
example.txt,并输出文件描述符、读取内容、文件信息与截断结果。 -
os.FileInfo
-
接口说明
-
os.FileInfo 是一个接口,表示文件元信息,常由 (*os.File).Stat()、os.Stat()、os.Lstat()、os.ReadDir() 等返回。
-
常用方法:
-
Name() string
-
Size() int64
-
Mode() os.FileMode
-
ModTime() time.Time
-
IsDir() bool
-
Sys() interface{} // 返回底层数据结构(平台相关)
-
完整示例(演示 Stat、Lstat、读取 Dir 的 FileInfo、以及 Sys 类型断言)
package main
import (
"fmt"
"os"
"time"
"runtime"
)
func main() {
// 先创建示例文件和目录
_ = os.WriteFile("fi_example.txt", []byte("data"), 0644)
_ = os.MkdirAll("fi_dir", 0755)
_ = os.WriteFile("fi_dir/inner.txt", []byte("inner"), 0644)
// 使用 os.Stat 获取 FileInfo
info, err := os.Stat("fi_example.txt")
if err != nil {
fmt.Println("Stat failed:", err)
return
}
// 使用 FileInfo 的方法
fmt.Println("Name:", info.Name())
fmt.Println("Size:", info.Size())
fmt.Println("Mode:", info.Mode().String())
fmt.Println("ModTime:", info.ModTime().Format(time.RFC3339))
fmt.Println("IsDir:", info.IsDir())
// Sys() 返回的类型平台相关,举例在 Unix 上通常是 *syscall.Stat_t
sys := info.Sys()
if sys != nil {
fmt.Printf("Sys type: %T\n", sys)
// 在 Unix 下可以进一步断言并读取 UID/GID(演示,不保证跨平台)
if runtime.GOOS != "windows" {
// 注意:此断言仅在类 Unix 系统有效
// import "syscall" 若需要访问具体字段
fmt.Println("底层系统数据可用(类 Unix 下可断言 *syscall.Stat_t)")
}
}
// 列出目录并打印每个文件的 FileInfo
dirEntries, err := os.ReadDir("fi_dir")
if err != nil {
fmt.Println("ReadDir failed:", err)
return
}
for _, de := range dirEntries {
// DirEntry 提供 Info() 获取 FileInfo(可能延迟读取)
fi, _ := de.Info()
fmt.Printf("dir entry: %s size=%d mode=%s isdir=%v\n",
fi.Name(), fi.Size(), fi.Mode().String(), fi.IsDir())
}
}
- 输出示例(时间/类型会根据系统不同):
Name: fi_example.txt
Size: 4
Mode: -rw-r--r--
ModTime: 2026-03-18T12:34:56Z
IsDir: false
Sys type: *syscall.Stat_t
dir entry: inner.txt size=5 mode:-rw-r--r-- isdir=false
-
os.FileMode
-
类型说明
-
os.FileMode 是一个位掩码类型(基于 uint32/uint32-ish),用于表示文件模式和权限。
-
常见用途:表示权限(rwx)、是否目录、是否为符号链接等特殊模式位。
-
常用方法/操作:
-
.String() string // 可读字符串表示,如
-rw-r--r-- -
.Perm() os.FileMode // 仅权限位(低 9 位)
-
按位检查: mode & os.ModeDir (判断是否目录)
-
常量示例: os.ModeDir, os.ModeAppend, os.ModeSymlink, os.ModeNamedPipe, os.ModeSocket, os.ModeDevice, os.ModeSetuid, os.ModeSetgid, os.ModeSticky
-
完整示例(解析并打印权限、判断目录/特殊位)
package main
import (
"fmt"
"os"
)
func main() {
// 创建示例文件与目录
_ = os.WriteFile("fm_example.txt", []byte("x"), 0640)
_ = os.MkdirAll("fm_dir", 0755)
// 获取 FileInfo
fiFile, _ := os.Stat("fm_example.txt")
fiDir, _ := os.Stat("fm_dir")
modeFile := fiFile.Mode()
modeDir := fiDir.Mode()
// 打印可读字符串及权限八进制表示
fmt.Println("file mode string:", modeFile.String()) // e.g. "-rw-r-----"
fmt.Printf("file perm (octal): %04o\n", modeFile.Perm())
fmt.Println("dir mode string:", modeDir.String()) // e.g. "drwxr-xr-x"
fmt.Printf("dir perm (octal): %04o\n", modeDir.Perm())
// 判断是否目录(使用 FileInfo.IsDir 更直观)
fmt.Println("file IsDir:", fiFile.IsDir())
fmt.Println("dir IsDir:", fiDir.IsDir())
// 检查特殊位示例(是否含 ModeDir)
if modeDir&os.ModeDir != 0 {
fmt.Println("modeDir has ModeDir bit set")
}
}
-
说明:
-
使用
fi.Mode().Perm()可以取得权限的数值部分,便于以八进制方式打印或比较。 -
fi.IsDir()是判断目录的简单方法;也可以使用fi.Mode() & os.ModeDir != 0。 -
os.FindProcess()
-
函数说明
-
*os.FindProcess(pid int) (os.Process, error) 用于根据进程 ID 查找一个表示该进程的 *os.Process 对象。
-
注意事项:
-
在某些平台(如 Unix),FindProcess 几乎总是返回一个 *os.Process(即使该 PID 不存在),真正是否存在通常要靠发送信号或其他探测手段确认。
-
在 Windows 上,如果 PID 无效可能返回错误。
-
操作(如 Signal、Kill)可能需要足够的权限(例如向其他用户的进程发送信号通常被拒绝)。
-
完整示例(传入 PID,尝试发送 SIGTERM / Kill,并等待简单反馈)
package main
import (
"fmt"
"os"
"strconv"
"syscall"
"time"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("用法: go run main.go <pid>")
return
}
pidStr := os.Args[1]
pid, err := strconv.Atoi(pidStr)
if err != nil {
fmt.Println("pid 必须为整数:", err)
return
}
proc, err := os.FindProcess(pid)
if err != nil {
fmt.Println("FindProcess 失败:", err)
return
}
// 在 Unix 上尝试发送 SIGTERM(优雅终止),在 Windows 上换成 Kill
// 注意:发送信号可能因权限或进程不存在而失败
fmt.Printf("尝试向 PID %d 发送 SIGTERM...\n", pid)
if err := proc.Signal(syscall.SIGTERM); err != nil {
fmt.Println("Signal 失败,尝试 Kill():", err)
// 尝试 Kill
if killErr := proc.Kill(); killErr != nil {
fmt.Println("Kill 也失败:", killErr)
} else {
fmt.Println("Kill 成功")
}
} else {
fmt.Println("Signal 发送成功(进程可能已终止或正在退出)")
}
// 可选:短暂等待并尝试释放(注意:Release 对于 FindProcess 得到的进程在不同平台含义不同)
time.Sleep(500 * time.Millisecond)
if err := proc.Release(); err != nil {
// Release 可能在某些情况下返回错误(或不必要)
fmt.Println("Release 返回:", err)
} else {
fmt.Println("Release 调用成功(若适用)")
}
}
-
使用示例(在类 Unix 环境):
-
编译并运行:
go run main.go 12345(假设 12345 是目标进程 PID) -
输出可能为:
尝试向 PID 12345 发送 SIGTERM...
Signal 发送成功(进程可能已终止或正在退出)
Release 调用成功(若适用)
-
若没有权限或进程不存在,Signal/Kill 会返回错误,程序会打印相应信息。
-
跨平台提示:
-
在 Windows 上没有 Unix 信号语义,建议只使用 Kill(或使用 platform-specific APIs)。
-
在容器/受限环境中,进程命名空间可能不同,PID 可能不是宿主上的 PID。
-
小结(要点回顾)
-
os.File:对文件句柄的操作集中地提供读/写/元信息/权限/截断/同步等方法,使用后必须
Close()。 -
os.FileInfo:接口层,提供文件元信息(Name/Size/Mode/ModTime/IsDir/Sys)。
-
os.FileMode:权限与特殊位的位掩码,使用
Mode().String()、.Perm()、按位检测来判断或显示。 -
os.FindProcess:根据 PID 获取 *os.Process;实际存在性、权限与效果需通过发送信号或平台 API 验证。
-
获取有效组 ID
获取当前进程的有效组 ID
os.Getegid() int -
说明:
-
主要用于 Unix 系统
-
与 Getgid 不同:Getegid 返回“生效权限”的组 ID
-
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("有效GID:", os.Getegid())
}
-
获取环境变量
获取指定环境变量的值
os.Getenv(key string) string -
说明:
-
如果不存在返回空字符串
-
可配合 os.Setenv 使用
-
示例
package main
import (
"fmt"
"os"
)
func main() {
os.Setenv("APP_ENV", "dev")
val := os.Getenv("APP_ENV")
fmt.Println("APP_ENV:", val)
// 不存在的变量
fmt.Println("NOT_EXIST:", os.Getenv("NOT_EXIST"))
}
-
获取有效用户 ID
获取当前进程的有效用户 ID
os.Geteuid() int -
说明:
-
Unix 系统使用
-
用于权限判断
-
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("有效UID:", os.Geteuid())
}
-
获取真实组 ID
获取当前进程的真实组 ID
os.Getgid() int -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("GID:", os.Getgid())
}
-
获取所属组列表
获取当前用户所属的所有组 ID
os.Getgroups() ([]int, error) -
示例
package main
import (
"fmt"
"os"
)
func main() {
groups, err := os.Getgroups()
if err != nil {
fmt.Println("获取失败:", err)
return
}
fmt.Println("groups:", groups)
}
-
获取内存页大小
获取操作系统内存页大小
os.Getpagesize() int -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("页面大小:", os.Getpagesize())
}
-
获取当前进程 ID
获取当前进程 ID
os.Getpid() int -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("当前PID:", os.Getpid())
}
-
获取父进程 ID
获取当前进程的父进程 ID
os.Getppid() int -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("父进程PID:", os.Getppid())
}
-
获取用户 ID
获取当前用户的真实用户 ID
os.Getuid() int -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("UID:", os.Getuid())
}
-
获取当前工作目录
获取当前程序的工作目录
os.Getwd() (string, error) -
说明:
-
通常配合 os.Chdir 使用
-
返回绝对路径
-
示例
package main
import (
"fmt"
"os"
)
func main() {
dir, err := os.Getwd()
if err != nil {
fmt.Println("获取失败:", err)
return
}
fmt.Println("当前目录:", dir)
}
-
小结
-
Getegid 👉 有效组ID
-
Geteuid 👉 有效用户ID
-
Getgid 👉 真实组ID
-
Getuid 👉 真实用户ID
-
Getgroups 👉 所属组
-
Getpagesize 👉 内存页大小
-
Getpid 👉 当前进程ID
-
Getppid 👉 父进程ID
-
Getwd 👉 当前目录
-
Getenv 👉 获取环境变量
-
获取主机名
获取当前操作系统的主机名
os.Hostname() (string, error) -
示例
package main
import (
"fmt"
"os"
)
func main() {
name, err := os.Hostname()
if err != nil {
fmt.Println("获取主机名失败:", err)
return
}
fmt.Println("Hostname:", name)
}
-
中断信号(Ctrl+C)
表示操作系统的中断信号
os.Interrupt (Signal) -
说明:
-
类型为:os.Signal
-
常用于捕获程序退出信号
-
示例(捕获 Ctrl+C)
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
ch := make(chan os.Signal, 1)
// 监听中断信号和终止信号
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
fmt.Println("程序运行中,按 Ctrl+C 退出...")
sig := <-ch
fmt.Println("收到信号:", sig)
fmt.Println("开始清理资源...")
}
-
判断文件是否存在
判断错误是否表示“文件已存在“
os.IsExist(err error) bool -
示例
package main
import (
"fmt"
"os"
)
func main() {
_, err := os.Stat("test.txt")
if err == nil {
fmt.Println("文件存在")
return
}
if os.IsExist(err) {
fmt.Println("文件已存在(IsExist判断)")
} else {
fmt.Println("文件不存在或其他错误:", err)
}
}
-
⚠️ 注意:
-
实际判断“文件是否存在”更推荐使用 os.IsNotExist(err)
-
判断文件不存在
判断错误是否表示“文件不存在“
os.IsNotExist(err error) bool -
示例(推荐用法)
package main
import (
"fmt"
"os"
)
func main() {
_, err := os.Stat("not_exist.txt")
if err == nil {
fmt.Println("文件存在")
return
}
if os.IsNotExist(err) {
fmt.Println("文件不存在")
} else {
fmt.Println("其他错误:", err)
}
}
-
判断是否路径分隔符
判断字符是否为路径分隔符
os.IsPathSeparator(c uint8) bool -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(os.IsPathSeparator('/')) // Unix: true
fmt.Println(os.IsPathSeparator('\\')) // Windows: true
fmt.Println(os.IsPathSeparator('a')) // false
}
-
判断权限错误
判断错误是否为权限问题
os.IsPermission(err error) bool -
示例
package main
import (
"fmt"
"os"
)
func main() {
// 尝试访问一个无权限文件(示例路径)
_, err := os.Open("/root/secret.txt")
if err != nil {
if os.IsPermission(err) {
fmt.Println("权限不足")
} else {
fmt.Println("其他错误:", err)
}
}
}
-
判断是否超时
判断错误是否为超时
os.IsTimeout(err error) bool -
示例(结合自定义超时错误)
package main
import (
"fmt"
"os"
"time"
)
func main() {
// 模拟一个超时错误(标准库中常见于网络操作)
err := &os.PathError{
Op: "read",
Path: "file.txt",
Err: fmt.Errorf("i/o timeout"),
}
if os.IsTimeout(err) {
fmt.Println("发生超时")
} else {
fmt.Println("不是超时错误:", err)
}
_ = time.Second // 防止未使用导入
}
-
获取信号编号
返回信号的底层编号
os.Interrupt.Signal() int -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Signal number:", os.Interrupt.Signal())
}
-
信号字符串表示
返回信号的字符串表示
os.Interrupt.String() string -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Signal name:", os.Interrupt.String())
}
-
小结
-
Hostname 👉 主机名
-
Interrupt 👉 Ctrl+C 信号
-
IsExist 👉 文件已存在(不常用于判断存在)
-
IsNotExist 👉 判断文件不存在(推荐)
-
IsPathSeparator 👉 判断路径分隔符
-
IsPermission 👉 权限错误判断
-
IsTimeout 👉 超时错误判断
-
Interrupt.Signal 👉 信号编号
-
Interrupt.String 👉 信号名称
-
强制终止进程信号
表示强制终止进程的信号
os.Kill (Signal) -
说明:
-
类型:os.Signal
-
Unix 对应 SIGKILL
-
不能被程序捕获(不同于 os.Interrupt)
-
示例(杀死指定进程)
package main
import (
"fmt"
"os"
"strconv"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("用法: go run main.go <pid>")
return
}
pid, _ := strconv.Atoi(os.Args[1])
proc, err := os.FindProcess(pid)
if err != nil {
fmt.Println("FindProcess失败:", err)
return
}
err = proc.Signal(os.Kill)
if err != nil {
fmt.Println("Kill失败:", err)
return
}
fmt.Println("进程已被强制终止:", pid)
}
-
修改符号链接所有者
修改符号链接本身的所有者
os.Lchown(name string, uid, gid int) error -
说明:
-
与 os.Chown 不同:不会作用到目标文件
-
仅在 Unix 有效
-
示例
package main
import (
"fmt"
"os"
)
func main() {
err := os.Lchown("symlink.txt", 1000, 1000)
if err != nil {
fmt.Println("Lchown失败:", err)
return
}
fmt.Println("修改符号链接所有者成功")
}
-
创建硬链接
创建一个硬链接
os.Link(oldname, newname string) error -
说明:
-
oldname:原文件
-
newname:新链接路径
-
两者共享同一 inode
-
示例
package main
import (
"fmt"
"os"
)
func main() {
// 创建源文件
err := os.WriteFile("source.txt", []byte("hello"), 0644)
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
// 创建硬链接
err = os.Link("source.txt", "hardlink.txt")
if err != nil {
fmt.Println("Link失败:", err)
return
}
fmt.Println("硬链接创建成功")
// 删除源文件,硬链接仍然存在
_ = os.Remove("source.txt")
data, _ := os.ReadFile("hardlink.txt")
fmt.Println("硬链接内容:", string(data))
}
-
链接错误类型
表示链接操作相关错误
os.LinkError struct -
字段:
-
Op string // 操作类型
-
Old string // 原路径
-
New string // 新路径
-
Err error // 底层错误
-
示例(类型断言获取详细错误)
package main
import (
"fmt"
"os"
)
func main() {
err := os.Link("not_exist.txt", "new.txt")
if err != nil {
if linkErr, ok := err.(*os.LinkError); ok {
fmt.Println("操作:", linkErr.Op)
fmt.Println("旧路径:", linkErr.Old)
fmt.Println("新路径:", linkErr.New)
fmt.Println("底层错误:", linkErr.Err)
} else {
fmt.Println("其他错误:", err)
}
}
}
-
获取环境变量(带存在判断)
获取环境变量,并返回是否存在
os.LookupEnv(key string) (string, bool) -
与 Getenv 区别:
-
Getenv 无法区分“未设置”和“空字符串”
-
LookupEnv 可以
-
示例
package main
import (
"fmt"
"os"
)
func main() {
os.Setenv("APP_ENV", "")
val, ok := os.LookupEnv("APP_ENV")
fmt.Println("值:", val)
fmt.Println("是否存在:", ok)
_, ok2 := os.LookupEnv("NOT_EXIST")
fmt.Println("NOT_EXIST 是否存在:", ok2)
}
-
获取文件信息(不跟随符号链接)
获取文件信息,但如果是符号链接,返回的是链接本身的信息
os.Lstat(name string) (os.FileInfo, error) -
与 Stat 区别:
-
Stat 👉 返回目标文件信息
-
Lstat 👉 返回链接自身信息
-
示例(对比 Stat 与 Lstat)
package main
import (
"fmt"
"os"
)
func main() {
// 创建目标文件
_ = os.WriteFile("target.txt", []byte("hello"), 0644)
// 创建符号链接(Windows 需要管理员权限)
_ = os.Symlink("target.txt", "link.txt")
// Stat(跟随链接)
statInfo, _ := os.Stat("link.txt")
// Lstat(不跟随)
lstatInfo, _ := os.Lstat("link.txt")
fmt.Println("Stat IsDir:", statInfo.IsDir())
fmt.Println("Stat Name:", statInfo.Name())
fmt.Println("Lstat Name:", lstatInfo.Name())
fmt.Println("Lstat Mode:", lstatInfo.Mode())
// 判断是否为符号链接
if lstatInfo.Mode()&os.ModeSymlink != 0 {
fmt.Println("这是一个符号链接")
}
}
-
小结
-
Kill 👉 强制终止信号
-
Lchown 👉 修改符号链接所有者
-
Link 👉 创建硬链接
-
LinkError 👉 链接错误结构
-
LookupEnv 👉 获取环境变量(带存在判断)
-
Lstat 👉 获取符号链接本身信息
-
创建目录
创建单层目录
os.Mkdir(name string, perm os.FileMode) error -
示例
package main
import (
"fmt"
"os"
)
func main() {
err := os.Mkdir("demo_dir", 0755)
if err != nil {
fmt.Println("创建失败:", err)
return
}
fmt.Println("目录创建成功")
}
-
递归创建目录
递归创建多级目录
os.MkdirAll(path string, perm os.FileMode) error -
示例
package main
import (
"fmt"
"os"
)
func main() {
err := os.MkdirAll("a/b/c", 0755)
if err != nil {
fmt.Println("创建失败:", err)
return
}
fmt.Println("多级目录创建成功")
}
-
创建临时目录
创建唯一临时目录
os.MkdirTemp(dir, pattern string) (string, error) -
示例
package main
import (
"fmt"
"os"
)
func main() {
dir, err := os.MkdirTemp("", "tmp_*")
if err != nil {
fmt.Println("创建失败:", err)
return
}
fmt.Println("临时目录:", dir)
defer os.RemoveAll(dir)
}
🔹 文件模式标志位(必须配合 FileMode 使用)
👉 所有 ModeXXX 必须配合以下函数使用:
- os.Stat()
- os.Lstat()
- (*os.File).Stat()
获取:
mode := fi.Mode()
文件为追加写模式
os.ModeAppend
-
配合:
-
os.Stat / File.Stat
-
示例
fi, _ := os.Stat("file.txt")
mode := fi.Mode()
if mode&os.ModeAppend != 0 {
fmt.Println("文件为追加模式")
}
字符设备(如终端)
os.ModeCharDevice
- 示例
fi, _ := os.Stat("/dev/tty")
if fi.Mode()&os.ModeCharDevice != 0 {
fmt.Println("字符设备")
}
设备文件
os.ModeDevice
- 示例
fi, _ := os.Stat("/dev/null")
if fi.Mode()&os.ModeDevice != 0 {
fmt.Println("设备文件")
}
目录
os.ModeDir
-
推荐方式:
-
fi.IsDir()
-
示例
fi, _ := os.Stat("demo_dir")
if fi.IsDir() {
fmt.Println("是目录")
}
独占文件
os.ModeExclusive
- 示例
fi, _ := os.Stat("file.txt")
if fi.Mode()&os.ModeExclusive != 0 {
fmt.Println("独占文件")
}
非常规文件
os.ModeIrregular
- 示例
fi, _ := os.Stat("file.txt")
if fi.Mode()&os.ModeIrregular != 0 {
fmt.Println("非常规文件")
}
命名管道(FIFO)
os.ModeNamedPipe
- 示例
fi, _ := os.Stat("mypipe")
if fi.Mode()&os.ModeNamedPipe != 0 {
fmt.Println("命名管道")
}
权限掩码(0777)
os.ModePerm
-
配合:
-
fi.Mode().Perm()
-
示例
fi, _ := os.Stat("file.txt")
fmt.Printf("权限: %04o\n", fi.Mode().Perm())
setgid 位
os.ModeSetgid
- 示例
fi, _ := os.Stat("file.txt")
if fi.Mode()&os.ModeSetgid != 0 {
fmt.Println("setgid")
}
setuid 位
os.ModeSetuid
- 示例
fi, _ := os.Stat("file.txt")
if fi.Mode()&os.ModeSetuid != 0 {
fmt.Println("setuid")
}
socket 文件
os.ModeSocket
- 示例
fi, _ := os.Stat("socket_file")
if fi.Mode()&os.ModeSocket != 0 {
fmt.Println("socket 文件")
}
粘滞位(如 /tmp)
os.ModeSticky
- 示例
fi, _ := os.Stat("/tmp")
if fi.Mode()&os.ModeSticky != 0 {
fmt.Println("粘滞位")
}
符号链接
os.ModeSymlink
-
⚠️ 必须使用:
-
os.Lstat()
-
示例
fi, _ := os.Lstat("link.txt")
if fi.Mode()&os.ModeSymlink != 0 {
fmt.Println("符号链接")
}
临时文件标志
os.ModeTemporary
- 示例
fi, _ := os.Stat("file.txt")
if fi.Mode()&os.ModeTemporary != 0 {
fmt.Println("临时文件")
}
类型掩码(用于提取类型)
os.ModeType
- 示例
fi, _ := os.Stat("file.txt")
fileType := fi.Mode() & os.ModeType
fmt.Println("类型位:", fileType)
🔥 总结(核心重点)
-
ModeXXX 必须配合:
-
os.Stat()
-
os.Lstat()
-
(*File).Stat()
-
使用方式:
mode := fi.Mode()
- 判断类型:
mode & os.ModeXXX != 0
- 获取权限:
mode.Perm()
-
从文件描述符创建文件对象
根据已有的文件描述符创建一个 *os.File 对象
os.NewFile(fd uintptr, name string) *os.File -
说明:
-
fd 通常来自系统调用或已有文件(如 Fd())
-
name 仅用于调试/显示,不影响实际文件
-
常用于与底层 syscall 或 C 交互
-
⚠️ 注意:
-
返回的 *os.File 需要手动 Close()
-
fd 必须是有效的文件描述符
-
示例(从标准输出构造 *os.File)
package main
import (
"fmt"
"os"
)
func main() {
// 1 表示 stdout(标准输出)
f := os.NewFile(uintptr(1), "stdout")
if f == nil {
fmt.Println("NewFile失败")
return
}
defer f.Close()
f.Write([]byte("Hello via NewFile\n"))
}
- 示例(结合已有文件描述符)
package main
import (
"fmt"
"os"
)
func main() {
// 打开文件
orig, err := os.OpenFile("test.txt", os.O_CREATE|os.O_RDWR, 0644)
if err != nil {
fmt.Println("打开失败:", err)
return
}
defer orig.Close()
// 获取 fd
fd := orig.Fd()
// 使用 fd 创建新的 File 对象
f := os.NewFile(fd, "copy")
f.WriteString("写入数据\n")
fmt.Println("写入完成")
}
-
封装系统调用错误
将系统调用错误包装为 *os.SyscallError 类型
os.NewSyscallError(syscall string, err error) error -
说明:
-
syscall:系统调用名称(如 “open”, “read”)
-
err:底层错误
-
返回值实现了 error 接口
-
作用:
-
提供更清晰的错误信息
-
可用于错误分类和处理
-
示例(包装错误)
package main
import (
"errors"
"fmt"
"os"
)
func main() {
// 模拟一个底层错误
baseErr := errors.New("permission denied")
err := os.NewSyscallError("open", baseErr)
fmt.Println("错误:", err)
// 类型断言
if sysErr, ok := err.(*os.SyscallError); ok {
fmt.Println("系统调用:", sysErr.Syscall)
fmt.Println("底层错误:", sysErr.Err)
}
}
- 示例(实际场景)
package main
import (
"fmt"
"os"
)
func main() {
_, err := os.Open("/root/secret.txt")
if err != nil {
// 包装为系统调用错误
err = os.NewSyscallError("open", err)
fmt.Println("错误:", err)
}
}
-
小结
-
NewFile 👉 从 fd 构造 *File(底层操作)
-
NewSyscallError 👉 包装系统调用错误
🔹 文件打开标志(必须配合 OpenFile 使用)
👉 以下所有 O_XXX 都是“标志位”,必须配合:
- os.OpenFile()
- os.Create(内部也是 OpenFile)
使用方式:
flag := os.O_CREATE | os.O_WRONLY | os.O_TRUNC
只读模式(默认值)
os.O_RDONLY
- 示例
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.OpenFile("test.txt", os.O_RDONLY, 0)
if err != nil {
fmt.Println("打开失败:", err)
return
}
defer f.Close()
buf := make([]byte, 100)
n, _ := f.Read(buf)
fmt.Println("读取内容:", string(buf[:n]))
}
只写模式
os.O_WRONLY
- 示例
f, _ := os.OpenFile("test.txt", os.O_WRONLY, 0644)
defer f.Close()
f.WriteString("写入数据")
读写模式
os.O_RDWR
- 示例
f, _ := os.OpenFile("test.txt", os.O_RDWR, 0644)
defer f.Close()
f.WriteString("hello")
f.Seek(0, 0)
buf := make([]byte, 10)
n, _ := f.Read(buf)
fmt.Println(string(buf[:n]))
追加写
os.O_APPEND
- 示例
f, _ := os.OpenFile("test.txt", os.O_APPEND|os.O_WRONLY, 0644)
defer f.Close()
f.WriteString("追加内容\n")
文件不存在则创建
os.O_CREATE
- 示例
f, _ := os.OpenFile("new.txt", os.O_CREATE|os.O_WRONLY, 0644)
defer f.Close()
f.WriteString("创建文件")
与 O_CREATE 一起使用,文件必须不存在
os.O_EXCL
- 示例
f, err := os.OpenFile("file.txt", os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
fmt.Println("文件已存在:", err)
return
}
defer f.Close()
同步写入
os.O_SYNC
-
特点:
-
安全性高
-
性能较低
-
示例
f, _ := os.OpenFile("sync.txt", os.O_CREATE|os.O_WRONLY|os.O_SYNC, 0644)
defer f.Close()
f.WriteString("立即写入磁盘")
打开文件时清空内容
os.O_TRUNC
- 示例
f, _ := os.OpenFile("test.txt", os.O_TRUNC|os.O_WRONLY, 0644)
defer f.Close()
f.WriteString("新内容")
-🔥 综合示例(推荐掌握)
package main
import (
"fmt"
"os"
)
func main() {
// 组合标志
flag := os.O_CREATE | os.O_RDWR | os.O_APPEND
f, err := os.OpenFile("demo.txt", flag, 0644)
if err != nil {
fmt.Println("打开失败:", err)
return
}
defer f.Close()
// 写入(追加)
f.WriteString("hello\n")
// 读取
f.Seek(0, 0)
buf := make([]byte, 100)
n, _ := f.Read(buf)
fmt.Println("内容:")
fmt.Println(string(buf[:n]))
}
-⚠️ 核心总结(必须掌握)
O_XXX 是标志位,必须配合 OpenFile
可组合使用:
os.O_CREATE | os.O_WRONLY | os.O_TRUNC
常见组合:
创建并写入:
os.O_CREATE | os.O_WRONLY
覆盖写:
os.O_CREATE | os.O_WRONLY | os.O_TRUNC
追加写:
os.O_CREATE | os.O_APPEND | os.O_WRONLY
读写:
os.O_RDWR
---
- 打开文件(只读)
### 以只读方式打开文件
`os.Open(name string) (*os.File, error)`
- 说明:
- 内部实现:
os.OpenFile(name, os.O_RDONLY, 0)
- 常用于读取文件
- 示例(完整)
```go
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("test.txt")
if err != nil {
fmt.Println("打开失败:", err)
return
}
defer f.Close()
buf := make([]byte, 100)
n, err := f.Read(buf)
if err != nil && err.Error() != "EOF" {
fmt.Println("读取失败:", err)
return
}
fmt.Println("读取内容:")
fmt.Println(string(buf[:n]))
}
-
打开/创建文件(核心函数)
打开或创建文件
os.OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) -
说明:
-
flag:O_XXX 标志组合
-
perm:权限(创建时生效)
👉 详细标志位说明见:O_XXX 部分
- 示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
flag := os.O_CREATE | os.O_RDWR | os.O_TRUNC
f, err := os.OpenFile("demo.txt", flag, 0644)
if err != nil {
fmt.Println("打开失败:", err)
return
}
defer f.Close()
f.WriteString("Hello OpenFile\n")
f.Seek(0, 0)
buf := make([]byte, 100)
n, _ := f.Read(buf)
fmt.Println("内容:")
fmt.Println(string(buf[:n]))
}
-
在根目录内打开文件(安全路径限制)
在指定根目录下安全地打开文件
os.OpenInRoot(dir, name string) (*os.File, error) -
说明:
-
name 不能跳出 dir(防止 ../ 攻击)
-
常用于沙箱、安全文件访问
-
示例
package main
import (
"fmt"
"os"
)
func main() {
// 只允许访问 ./data 目录
f, err := os.OpenInRoot("./data", "file.txt")
if err != nil {
fmt.Println("打开失败:", err)
return
}
defer f.Close()
fmt.Println("安全打开成功")
}
-
打开根目录句柄
打开一个目录作为“根目录句柄“
os.OpenRoot(name string) (*os.File, error) -
说明:
-
返回的 *File 可作为安全文件系统根
-
通常配合 OpenInRoot 使用
-
示例
package main
import (
"fmt"
"os"
)
func main() {
root, err := os.OpenRoot("./data")
if err != nil {
fmt.Println("打开根目录失败:", err)
return
}
defer root.Close()
fmt.Println("根目录已打开:", root.Name())
}
🔥 对比总结
- os.Open 👉 只读打开(最简单)
- os.OpenFile 👉 最强(支持所有模式)
- os.OpenInRoot 👉 安全打开(防路径穿越)
- os.OpenRoot 👉 获取目录句柄(配合安全访问)
⚠️ 关键注意点
- 所有返回 *os.File 的函数都必须:
defer f.Close()
- OpenInRoot / OpenRoot 适用于安全场景(如 Web、沙箱)
-
路径错误类型
表示与路径操作相关的错误
os.PathError struct -
字段:
-
Op string // 操作(open / stat / read 等)
-
Path string // 路径
-
Err error // 底层错误
-
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
_, err := os.Open("not_exist.txt")
if err != nil {
if pe, ok := err.(*os.PathError); ok {
fmt.Println("操作:", pe.Op)
fmt.Println("路径:", pe.Path)
fmt.Println("错误:", pe.Err)
} else {
fmt.Println("其他错误:", err)
}
}
}
-
路径列表分隔符
用于分隔路径列表
os.PathListSeparator (byte) -
说明:
-
Unix:
: -
Windows:
; -
示例
package main
import (
"fmt"
"os"
"strings"
)
func main() {
path := os.Getenv("PATH")
parts := strings.Split(path, string(os.PathListSeparator))
for i, p := range parts {
fmt.Println(i, p)
}
}
-
路径分隔符
表示文件路径分隔符
os.PathSeparator (byte) -
说明:
-
Unix:
/ -
Windows:
\ -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("路径分隔符:", string(os.PathSeparator))
}
-
创建管道
创建一个同步内存管道
os.Pipe() (*os.File, *os.File, error) -
返回:
-
r:读端
-
w:写端
-
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
r, w, err := os.Pipe()
if err != nil {
fmt.Println("创建失败:", err)
return
}
defer r.Close()
defer w.Close()
// 写入
go func() {
w.Write([]byte("hello pipe"))
w.Close()
}()
buf := make([]byte, 100)
n, _ := r.Read(buf)
fmt.Println("读取:", string(buf[:n]))
}
-
进程属性
用于创建新进程时的属性配置
os.ProcAttr struct -
常用字段:
-
Dir string // 工作目录
-
Env []string // 环境变量
-
Files []*os.File // 文件描述符(stdin stdout stderr)
-
示例(结合 StartProcess)
package main
import (
"fmt"
"os"
)
func main() {
attr := &os.ProcAttr{
Dir: "",
Env: os.Environ(),
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
}
proc, err := os.StartProcess("/bin/ls", []string{"ls"}, attr)
if err != nil {
fmt.Println("启动失败:", err)
return
}
fmt.Println("进程ID:", proc.Pid)
}
-
进程对象
表示一个系统进程
os.Process struct -
常用方法:
-
.Pid int
-
.Kill() error
-
.Signal(sig os.Signal) error
-
.Wait() (*os.ProcessState, error)
-
.Release() error
-
示例(完整)
package main
import (
"fmt"
"os"
"time"
)
func main() {
attr := &os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
}
proc, err := os.StartProcess("/bin/sleep", []string{"sleep", "2"}, attr)
if err != nil {
fmt.Println("启动失败:", err)
return
}
fmt.Println("进程ID:", proc.Pid)
// 等待进程结束
state, err := proc.Wait()
if err != nil {
fmt.Println("等待失败:", err)
return
}
fmt.Println("进程结束:", state.Exited())
fmt.Println("退出码:", state.ExitCode())
time.Sleep(time.Second)
}
-
进程状态
表示进程执行后的状态
os.ProcessState struct -
常用方法:
-
.Exited() bool
-
.Success() bool
-
.ExitCode() int
-
.UserTime()
-
.SystemTime()
-
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
attr := &os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
}
proc, err := os.StartProcess("/bin/echo", []string{"echo", "hello"}, attr)
if err != nil {
fmt.Println("启动失败:", err)
return
}
state, err := proc.Wait()
if err != nil {
fmt.Println("等待失败:", err)
return
}
fmt.Println("是否退出:", state.Exited())
fmt.Println("是否成功:", state.Success())
fmt.Println("退出码:", state.ExitCode())
fmt.Println("用户时间:", state.UserTime())
fmt.Println("系统时间:", state.SystemTime())
}
🔥 总结
- PathError 👉 路径错误结构
- PathListSeparator 👉 PATH 分隔符
- PathSeparator 👉 路径分隔符
- Pipe 👉 内存管道(进程通信)
- ProcAttr 👉 进程启动参数
- Process 👉 进程对象
- ProcessState 👉 进程状态
-
读取目录
读取目录内容
os.ReadDir(name string) ([]os.DirEntry, error) -
说明:
-
返回 DirEntry(懒加载信息)
-
需要调用 Info() 才获取详细信息
-
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
entries, err := os.ReadDir(".")
if err != nil {
fmt.Println("读取失败:", err)
return
}
for _, e := range entries {
fmt.Println("名称:", e.Name())
fmt.Println("是否目录:", e.IsDir())
// 获取详细信息
info, _ := e.Info()
fmt.Println("大小:", info.Size())
fmt.Println("------")
}
}
-
读取文件
一次性读取整个文件内容
os.ReadFile(name string) ([]byte, error) -
示例
package main
import (
"fmt"
"os"
)
func main() {
data, err := os.ReadFile("test.txt")
if err != nil {
fmt.Println("读取失败:", err)
return
}
fmt.Println("内容:")
fmt.Println(string(data))
}
-
读取符号链接
获取符号链接指向的目标路径
os.Readlink(name string) (string, error) -
示例
package main
import (
"fmt"
"os"
)
func main() {
// 创建示例
os.WriteFile("target.txt", []byte("hello"), 0644)
os.Symlink("target.txt", "link.txt")
target, err := os.Readlink("link.txt")
if err != nil {
fmt.Println("读取失败:", err)
return
}
fmt.Println("链接指向:", target)
}
-
删除文件
删除文件或空目录
os.Remove(name string) error -
示例
package main
import (
"fmt"
"os"
)
func main() {
os.WriteFile("del.txt", []byte("test"), 0644)
err := os.Remove("del.txt")
if err != nil {
fmt.Println("删除失败:", err)
return
}
fmt.Println("删除成功")
}
-
递归删除
删除目录及其所有内容
os.RemoveAll(path string) error -
⚠️ 危险操作(慎用)
-
示例
package main
import (
"fmt"
"os"
)
func main() {
os.MkdirAll("tmp/a/b", 0755)
err := os.RemoveAll("tmp")
if err != nil {
fmt.Println("删除失败:", err)
return
}
fmt.Println("目录已删除")
}
-
重命名/移动文件
重命名或移动文件/目录
os.Rename(oldpath, newpath string) error -
示例
package main
import (
"fmt"
"os"
)
func main() {
os.WriteFile("old.txt", []byte("hello"), 0644)
err := os.Rename("old.txt", "new.txt")
if err != nil {
fmt.Println("重命名失败:", err)
return
}
fmt.Println("重命名成功")
}
-
根目录句柄类型
-
os.Root
表示一个受限的“根目录句柄”(用于安全文件访问)。
-
说明:
-
通常由 os.OpenRoot 获取
-
用于限制文件访问范围(防止路径逃逸)
-
常见于安全沙箱、Web服务
-
示例
package main
import (
"fmt"
"os"
)
func main() {
root, err := os.OpenRoot("./data")
if err != nil {
fmt.Println("打开失败:", err)
return
}
defer root.Close()
fmt.Println("Root:", root.Name())
}
🔥 总结
- ReadDir 👉 读取目录(推荐)
- ReadFile 👉 一次性读文件
- Readlink 👉 读取符号链接
- Remove 👉 删除文件
- RemoveAll 👉 递归删除(危险)
- Rename 👉 重命名/移动
- Root 👉 安全根目录句柄
-
判断是否为同一文件
判断两个 FileInfo 是否指向同一个文件
os.SameFile(fi1, fi2 os.FileInfo) bool -
说明:
-
常用于判断硬链接或同一文件
-
不能通过路径判断,必须用 FileInfo
-
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
// 创建文件
os.WriteFile("a.txt", []byte("hello"), 0644)
// 创建硬链接
os.Link("a.txt", "b.txt")
fi1, _ := os.Stat("a.txt")
fi2, _ := os.Stat("b.txt")
if os.SameFile(fi1, fi2) {
fmt.Println("是同一个文件")
} else {
fmt.Println("不是同一个文件")
}
}
-
设置环境变量
设置环境变量
os.Setenv(key, value string) error -
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
err := os.Setenv("APP_MODE", "dev")
if err != nil {
fmt.Println("设置失败:", err)
return
}
fmt.Println("APP_MODE:", os.Getenv("APP_MODE"))
}
-
信号接口
表示操作系统信号类型接口
os.Signal (interface) -
说明:
-
常用于 signal.Notify
-
实现类型如 syscall.Signal
-
示例(捕获信号)
package main
import (
"fmt"
"os"
"os/signal"
)
func main() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
fmt.Println("等待信号(Ctrl+C)...")
sig := <-ch
fmt.Println("收到信号:", sig)
}
-
启动进程
启动一个新进程
os.StartProcess(name string, argv []string, attr *os.ProcAttr) (*os.Process, error) -
说明:
-
name:程序路径
-
argv:参数列表(第一个通常是程序名)
-
attr:进程属性(见 ProcAttr)
-
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
attr := &os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
}
proc, err := os.StartProcess("/bin/echo", []string{"echo", "Hello"}, attr)
if err != nil {
fmt.Println("启动失败:", err)
return
}
state, _ := proc.Wait()
fmt.Println("退出码:", state.ExitCode())
}
-
获取文件信息
获取文件信息(跟随符号链接)
os.Stat(name string) (os.FileInfo, error) -
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
os.WriteFile("file.txt", []byte("data"), 0644)
fi, err := os.Stat("file.txt")
if err != nil {
fmt.Println("获取失败:", err)
return
}
fmt.Println("名称:", fi.Name())
fmt.Println("大小:", fi.Size())
fmt.Println("是否目录:", fi.IsDir())
fmt.Println("权限:", fi.Mode())
}
-
标准错误输出
标准错误输出(文件描述符 2)
os.Stderr (*os.File) -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Fprintln(os.Stderr, "这是错误输出")
}
-
标准输入
标准输入(文件描述符 0)
os.Stdin (*os.File) -
示例
package main
import (
"fmt"
"os"
)
func main() {
buf := make([]byte, 100)
fmt.Println("请输入内容:")
n, _ := os.Stdin.Read(buf)
fmt.Println("你输入的是:", string(buf[:n]))
}
-
标准输出
标准输出(文件描述符 1)
os.Stdout (*os.File) -
示例
package main
import (
"fmt"
"os"
)
func main() {
fmt.Fprintln(os.Stdout, "输出到标准输出")
}
-
创建符号链接
创建符号链接
os.Symlink(oldname, newname string) error -
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
os.WriteFile("target.txt", []byte("hello"), 0644)
err := os.Symlink("target.txt", "link.txt")
if err != nil {
fmt.Println("创建失败:", err)
return
}
fmt.Println("符号链接创建成功")
}
-
系统调用错误类型
表示系统调用错误
os.SyscallError struct -
字段:
-
Syscall string
-
Err error
-
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
_, err := os.Open("/root/secret.txt")
if err != nil {
if se, ok := err.(*os.SyscallError); ok {
fmt.Println("调用:", se.Syscall)
fmt.Println("错误:", se.Err)
} else {
fmt.Println("其他错误:", err)
}
}
}
🔥 总结
- SameFile 👉 判断是否同一文件
- Setenv 👉 设置环境变量
- Signal 👉 信号接口
- StartProcess 👉 启动进程
- Stat 👉 获取文件信息
- Stderr / Stdin / Stdout 👉 标准IO
- Symlink 👉 创建符号链接
- SyscallError 👉 系统调用错误
-
获取临时目录
返回系统默认的临时目录路径
os.TempDir() string -
说明:
-
Unix:通常为 /tmp
-
Windows:如 C:\Users\xxx\AppData\Local\Temp
-
示例(完整)
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
tmp := os.TempDir()
fmt.Println("临时目录:", tmp)
// 在临时目录创建文件
file := filepath.Join(tmp, "demo.txt")
err := os.WriteFile(file, []byte("temp data"), 0644)
if err != nil {
fmt.Println("写入失败:", err)
return
}
fmt.Println("文件创建:", file)
// 清理
os.Remove(file)
}
-
截断文件
修改文件大小(截断或扩展)
os.Truncate(name string, size int64) error -
说明:
-
size 小于原大小 👉 截断
-
size 大于原大小 👉 用 0 填充
-
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
os.WriteFile("truncate.txt", []byte("HelloWorld"), 0644)
// 截断为 5 字节
err := os.Truncate("truncate.txt", 5)
if err != nil {
fmt.Println("截断失败:", err)
return
}
data, _ := os.ReadFile("truncate.txt")
fmt.Println("内容:", string(data)) // Hello
}
-
删除环境变量
删除指定环境变量
os.Unsetenv(key string) error -
示例(完整)
package main
import (
"fmt"
"os"
)
func main() {
os.Setenv("TEST_ENV", "123")
fmt.Println("设置:", os.Getenv("TEST_ENV"))
os.Unsetenv("TEST_ENV")
fmt.Println("删除后:", os.Getenv("TEST_ENV"))
}
-
用户缓存目录
返回用户缓存目录路径
os.UserCacheDir() (string, error) -
说明:
-
Linux:~/.cache
-
Windows:AppData\Local
-
macOS:~/Library/Caches
-
示例
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
dir, err := os.UserCacheDir()
if err != nil {
fmt.Println("获取失败:", err)
return
}
fmt.Println("缓存目录:", dir)
// 创建缓存文件
file := filepath.Join(dir, "app.cache")
os.WriteFile(file, []byte("cache"), 0644)
}
-
用户配置目录
返回用户配置目录
os.UserConfigDir() (string, error) -
说明:
-
Linux:~/.config
-
Windows:AppData\Roaming
-
macOS:~/Library/Application Support
-
示例
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
dir, err := os.UserConfigDir()
if err != nil {
fmt.Println("获取失败:", err)
return
}
fmt.Println("配置目录:", dir)
conf := filepath.Join(dir, "app.conf")
os.WriteFile(conf, []byte("config"), 0644)
}
-
用户主目录
获取当前用户主目录
os.UserHomeDir() (string, error) -
示例(完整)
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
home, err := os.UserHomeDir()
if err != nil {
fmt.Println("获取失败:", err)
return
}
fmt.Println("Home目录:", home)
// 创建测试文件
file := filepath.Join(home, "test_home.txt")
os.WriteFile(file, []byte("hello"), 0644)
fmt.Println("文件创建:", file)
}
🔥 总结
- TempDir 👉 临时目录
- Truncate 👉 截断文件
- Unsetenv 👉 删除环境变量
- UserCacheDir 👉 缓存目录
- UserConfigDir 👉 配置目录
- UserHomeDir 👉 用户主目录
写入内容到已存在文件 os.WriteFile()