Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

go语言

文件操作


🔹 os.Args


📌 说明

  • 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)
}
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)
}
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")) // 空

// 假设已有 embed.FS
err := os.CopyFS("./output", myFS)
if err != nil {
fmt.Println("复制失败:", err)
}

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())
}

fsys := os.DirFS("./static")

data, _ := fs.ReadFile(fsys, "index.html")
fmt.Println(string(data))

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)

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.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"))
}

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println("有效UID:", os.Geteuid())
}

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println("GID:", os.Getgid())
}

package main

import (
"fmt"
"os"
)

func main() {
groups, err := os.Getgroups()
if err != nil {
fmt.Println("获取失败:", err)
return
}
fmt.Println("groups:", groups)
}

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println("页面大小:", os.Getpagesize())
}

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println("当前PID:", os.Getpid())
}

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println("父进程PID:", os.Getppid())
}

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println("UID:", os.Getuid())
}

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 👉 获取环境变量


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("开始清理资源...")
}

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)


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)
}
}

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
}

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)
}
}
}

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 // 防止未使用导入
}

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println("Signal number:", os.Interrupt.Signal())
}

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)
}

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 👉 获取符号链接本身信息


package main

import (
"fmt"
"os"
)

func main() {
err := os.Mkdir("demo_dir", 0755)
if err != nil {
fmt.Println("创建失败:", err)
return
}
fmt.Println("目录创建成功")
}

package main

import (
"fmt"
"os"
)

func main() {
err := os.MkdirAll("a/b/c", 0755)
if err != nil {
fmt.Println("创建失败:", err)
return
}
fmt.Println("多级目录创建成功")
}

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("安全打开成功")
}

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)
}
}
}

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)
}
}

package main

import (
"fmt"
"os"
)

func main() {
fmt.Println("路径分隔符:", string(os.PathSeparator))
}

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("------")
}
}

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))
}

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)
}

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("删除成功")
}

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("目录已删除")
}

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 👉 安全根目录句柄

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"))
}

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())
}

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())
}

package main

import (
"fmt"
"os"
)

func main() {
fmt.Fprintln(os.Stderr, "这是错误输出")
}

package main

import (
"fmt"
"os"
)

func main() {
buf := make([]byte, 100)

fmt.Println("请输入内容:")

n, _ := os.Stdin.Read(buf)

fmt.Println("你输入的是:", string(buf[:n]))
}

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 👉 系统调用错误

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
}

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)
}

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()