Go语言中的文件与目录操作详解

慢慢就习惯了,情绪波动也没有那么大了,委屈了我就哭,我自己安慰自己,我不需要别人

Posted by yishuifengxiao on 2023-12-21

目录操作

创建目录

package main

import (
"fmt"
"os"
)

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

// 创建多级目录
err = os.MkdirAll("testdir/subdir1/subdir2", 0755)
if err != nil {
fmt.Println("创建多级目录失败:", err)
return
}
fmt.Println("多级目录创建成功")
}

删除目录

package main

import (
"fmt"
"os"
)

func main() {
// 删除空目录
err := os.Remove("testdir")
if err != nil {
fmt.Println("删除目录失败:", err)
} else {
fmt.Println("目录删除成功")
}

// 递归删除目录及其内容
err = os.RemoveAll("testdir")
if err != nil {
fmt.Println("递归删除目录失败:", err)
} else {
fmt.Println("目录递归删除成功")
}
}

判断目录是否存在

package main

import (
"fmt"
"os"
)

func isDirExists(path string) bool {
info, err := os.Stat(path)
if os.IsNotExist(err) {
return false
}
return info.IsDir()
}

func main() {
path := "testdir"
if isDirExists(path) {
fmt.Printf("目录 %s 存在\n", path)
} else {
fmt.Printf("目录 %s 不存在\n", path)
}
}

文件操作

创建文件

package main

import (
"fmt"
"os"
)

func main() {
// 创建文件
file, err := os.Create("test.txt")
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
defer file.Close()

fmt.Println("文件创建成功")
}

写入文件

package main

import (
"fmt"
"os"
)

func main() {
// 方式1: 使用os.WriteFile (一次性写入)
content := []byte("Hello, Go!\n这是一行中文文本。")
err := os.WriteFile("test.txt", content, 0644)
if err != nil {
fmt.Println("写入文件失败:", err)
return
}
fmt.Println("文件写入成功")

// 方式2: 使用文件句柄逐步写入
file, err := os.OpenFile("test2.txt", os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

_, err = file.WriteString("第一行内容\n")
if err != nil {
fmt.Println("写入文件失败:", err)
return
}

_, err = file.Write([]byte("第二行内容\n"))
if err != nil {
fmt.Println("写入文件失败:", err)
return
}

fmt.Println("逐步写入文件成功")
}

读取文件

package main

import (
"fmt"
"os"
"io"
)

func main() {
// 方式1: 一次性读取整个文件
content, err := os.ReadFile("test.txt")
if err != nil {
fmt.Println("读取文件失败:", err)
return
}
fmt.Printf("文件内容:\n%s\n", string(content))

// 方式2: 使用文件句柄逐步读取
file, err := os.Open("test.txt")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

fmt.Println("逐步读取文件内容:")
buffer := make([]byte, 16) // 每次读取16字节
for {
n, err := file.Read(buffer)
if err != nil && err != io.EOF {
fmt.Println("读取文件失败:", err)
return
}
if n == 0 {
break
}
fmt.Print(string(buffer[:n]))
}
}

文件信息与属性

package main

import (
"fmt"
"os"
"time"
)

func main() {
fileInfo, err := os.Stat("test.txt")
if err != nil {
fmt.Println("获取文件信息失败:", err)
return
}

fmt.Printf("文件名: %s\n", fileInfo.Name())
fmt.Printf("文件大小: %d 字节\n", fileInfo.Size())
fmt.Printf("权限: %s\n", fileInfo.Mode())
fmt.Printf("最后修改时间: %s\n", fileInfo.ModTime().Format(time.RFC3339))
fmt.Printf("是否是目录: %t\n", fileInfo.IsDir())
}

重命名和移动文件

package main

import (
"fmt"
"os"
)

func main() {
// 重命名文件
err := os.Rename("test.txt", "renamed.txt")
if err != nil {
fmt.Println("重命名文件失败:", err)
return
}
fmt.Println("文件重命名成功")

// 移动文件到子目录
os.MkdirAll("subdir", 0755)
err = os.Rename("renamed.txt", "subdir/moved.txt")
if err != nil {
fmt.Println("移动文件失败:", err)
return
}
fmt.Println("文件移动成功")
}

删除文件

package main

import (
"fmt"
"os"
)

func main() {
err := os.Remove("test.txt")
if err != nil {
fmt.Println("删除文件失败:", err)
return
}
fmt.Println("文件删除成功")
}

遍历文件夹

使用os.ReadDir (Go 1.16+)

package main

import (
"fmt"
"os"
"path/filepath"
)

func main() {
entries, err := os.ReadDir(".")
if err != nil {
fmt.Println("读取目录失败:", err)
return
}

fmt.Println("当前目录内容:")
for _, entry := range entries {
info, err := entry.Info()
if err != nil {
fmt.Printf("获取文件信息失败: %v\n", err)
continue
}

fileType := "文件"
if entry.IsDir() {
fileType = "目录"
}

fmt.Printf("%s: %s (%d bytes)\n",
entry.Name(), fileType, info.Size())
}
}

使用filepath.Walk

package main

import (
"fmt"
"os"
"path/filepath"
)

func main() {
fmt.Println("遍历当前目录及其子目录:")
err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("访问路径 %s 时出错: %v\n", path, err)
return nil
}

fileType := "文件"
if info.IsDir() {
fileType = "目录"
}

// 跳过.git目录
if info.IsDir() && info.Name() == ".git" {
fmt.Printf("跳过目录: %s\n", path)
return filepath.SkipDir
}

relPath, _ := filepath.Rel(".", path)
fmt.Printf("%s: %s (%d bytes)\n",
relPath, fileType, info.Size())
return nil
})

if err != nil {
fmt.Printf("遍历目录失败: %v\n", err)
}
}

使用filepath.WalkDir (Go 1.16+)

package main

import (
"fmt"
"os"
"path/filepath"
)

func main() {
fmt.Println("使用WalkDir遍历目录:")
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
if err != nil {
fmt.Printf("访问路径 %s 时出错: %v\n", path, err)
return nil
}

fileType := "文件"
if d.IsDir() {
fileType = "目录"
}

info, err := d.Info()
if err != nil {
fmt.Printf("获取文件信息失败: %v\n", err)
return nil
}

relPath, _ := filepath.Rel(".", path)
fmt.Printf("%s: %s (%d bytes)\n",
relPath, fileType, info.Size())
return nil
})

if err != nil {
fmt.Printf("遍历目录失败: %v\n", err)
}
}

高级文件操作

检查文件是否存在

package main

import (
"fmt"
"os"
)

func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}

func main() {
filename := "test.txt"
if fileExists(filename) {
fmt.Printf("文件 %s 存在\n", filename)
} else {
fmt.Printf("文件 %s 不存在\n", filename)
}
}

复制文件

package main

import (
"fmt"
"io"
"os"
)

func copyFile(src, dst string) error {
source, err := os.Open(src)
if err != nil {
return err
}
defer source.Close()

destination, err := os.Create(dst)
if err != nil {
return err
}
defer destination.Close()

_, err = io.Copy(destination, source)
return err
}

func main() {
err := copyFile("source.txt", "destination.txt")
if err != nil {
fmt.Println("复制文件失败:", err)
return
}
fmt.Println("文件复制成功")
}

处理文件路径

package main

import (
"fmt"
"path/filepath"
)

func main() {
// 拼接路径
path := filepath.Join("dir", "subdir", "file.txt")
fmt.Println("拼接后的路径:", path)

// 获取路径的目录部分
dir := filepath.Dir(path)
fmt.Println("目录部分:", dir)

// 获取路径的文件名部分
filename := filepath.Base(path)
fmt.Println("文件名部分:", filename)

// 获取文件扩展名
ext := filepath.Ext(path)
fmt.Println("文件扩展名:", ext)

// 获取相对路径
rel, err := filepath.Rel("/usr/local", "/usr/local/bin/go")
if err != nil {
fmt.Println("获取相对路径失败:", err)
} else {
fmt.Println("相对路径:", rel)
}

// 清理路径中的冗余部分
cleanPath := filepath.Clean("./dir/.././file.txt")
fmt.Println("清理后的路径:", cleanPath)
}

综合示例:统计目录大小

package main

import (
"fmt"
"os"
"path/filepath"
)

func dirSize(path string) (int64, error) {
var size int64
err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
size += info.Size()
}
return nil
})
return size, err
}

func main() {
if len(os.Args) < 2 {
fmt.Println("请指定要统计的目录")
return
}

dir := os.Args[1]
size, err := dirSize(dir)
if err != nil {
fmt.Printf("统计目录大小失败: %v\n", err)
return
}

// 以更友好的格式显示大小
var sizeStr string
switch {
case size > 1<<30:
sizeStr = fmt.Sprintf("%.2f GB", float64(size)/(1<<30))
case size > 1<<20:
sizeStr = fmt.Sprintf("%.2f MB", float64(size)/(1<<20))
case size > 1<<10:
sizeStr = fmt.Sprintf("%.2f KB", float64(size)/(1<<10))
default:
sizeStr = fmt.Sprintf("%d B", size)
}

fmt.Printf("目录 %s 的大小: %s\n", dir, sizeStr)
}

Go语言中的文件读写模式详解

Go语言提供了灵活的文件操作方式,支持多种读写模式。下面将详细说明各种文件读写模式,包括覆盖、追加等方式,并提供详细的代码示例。

文件打开模式

在Go中,我们使用os.OpenFile函数来打开文件,并通过组合不同的标志(flags)来指定文件打开模式:

file, err := os.OpenFile(filename, flags, permission)

常用的文件打开标志包括:

  • os.O_RDONLY: 只读模式
  • os.O_WRONLY: 只写模式
  • os.O_RDWR: 读写模式
  • os.O_CREATE: 如果文件不存在则创建
  • os.O_APPEND: 追加模式
  • os.O_TRUNC: 如果文件存在则清空
  • os.O_EXCL: 与O_CREATE一起使用,文件必须不存在

这些模式可以通过按位或(|)组合使用。

各种读写模式示例

只读模式

package main

import (
"fmt"
"os"
)

func main() {
// 只读模式打开文件
file, err := os.OpenFile("example.txt", os.O_RDONLY, 0644)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

// 读取文件内容
data := make([]byte, 1024)
count, err := file.Read(data)
if err != nil {
fmt.Println("读取文件失败:", err)
return
}

fmt.Printf("读取了 %d 字节: %s\n", count, string(data[:count]))
}

覆盖写入模式(创建新文件或清空已有文件)

package main

import (
"fmt"
"os"
)

func main() {
// 写入模式,如果文件不存在则创建,如果存在则清空
file, err := os.OpenFile("example.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

// 写入内容(会覆盖原有内容)
content := "这是新内容,会覆盖文件原有内容。\n"
_, err = file.WriteString(content)
if err != nil {
fmt.Println("写入文件失败:", err)
return
}

fmt.Println("文件覆盖写入成功")
}

追加写入模式

package main

import (
"fmt"
"os"
)

func main() {
// 追加模式,如果文件不存在则创建,如果存在则在末尾追加
file, err := os.OpenFile("example.txt", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

// 追加内容
content := "这是在文件末尾追加的内容。\n"
_, err = file.WriteString(content)
if err != nil {
fmt.Println("追加内容失败:", err)
return
}

fmt.Println("文件追加写入成功")
}

读写模式(不清空)

package main

import (
"fmt"
"os"
)

func main() {
// 读写模式,如果文件不存在则创建,如果存在则保留内容
file, err := os.OpenFile("example.txt", os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

// 读取文件内容
data := make([]byte, 1024)
count, err := file.Read(data)
if err != nil {
fmt.Println("读取文件失败:", err)
return
}
fmt.Printf("原文件内容: %s\n", string(data[:count]))

// 将文件指针重置到开头
_, err = file.Seek(0, 0)
if err != nil {
fmt.Println("重置文件指针失败:", err)
return
}

// 写入新内容(会从文件开头覆盖原有内容)
newContent := "这是从开头写入的新内容。\n"
_, err = file.WriteString(newContent)
if err != nil {
fmt.Println("写入文件失败:", err)
return
}

fmt.Println("文件读写操作成功")
}

读写模式并清空

package main

import (
"fmt"
"os"
)

func main() {
// 读写模式,如果文件不存在则创建,如果存在则清空
file, err := os.OpenFile("example.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

// 写入内容
content := "这是清空后写入的新内容。\n"
_, err = file.WriteString(content)
if err != nil {
fmt.Println("写入文件失败:", err)
return
}

// 将文件指针重置到开头
_, err = file.Seek(0, 0)
if err != nil {
fmt.Println("重置文件指针失败:", err)
return
}

// 读取文件内容验证
data := make([]byte, 1024)
count, err := file.Read(data)
if err != nil {
fmt.Println("读取文件失败:", err)
return
}

fmt.Printf("文件内容: %s\n", string(data[:count]))
fmt.Println("文件清空后读写操作成功")
}

追加读写模式

package main

import (
"fmt"
"os"
)

func main() {
// 追加读写模式,如果文件不存在则创建,如果存在则可以在末尾追加,同时也可以读取
file, err := os.OpenFile("example.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()

// 读取文件内容
data := make([]byte, 1024)
count, err := file.Read(data)
if err != nil {
fmt.Println("读取文件失败:", err)
return
}
fmt.Printf("原文件内容: %s\n", string(data[:count]))

// 注意:在追加模式下,写入操作总是在文件末尾,不受读取位置影响
// 追加内容
appendContent := "这是在文件末尾追加的内容。\n"
_, err = file.WriteString(appendContent)
if err != nil {
fmt.Println("追加内容失败:", err)
return
}

fmt.Println("文件追加读写操作成功")
}

互斥创建模式

package main

import (
"fmt"
"os"
)

func main() {
// 互斥创建模式,文件必须不存在,否则会报错
file, err := os.OpenFile("example.txt", os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
if os.IsExist(err) {
fmt.Println("文件已存在,创建失败")
} else {
fmt.Println("创建文件失败:", err)
}
return
}
defer file.Close()

// 写入内容
content := "这是在新创建的文件中写入的内容。\n"
_, err = file.WriteString(content)
if err != nil {
fmt.Println("写入文件失败:", err)
return
}

fmt.Println("文件创建并写入成功")
}

使用os包便捷函数

除了使用os.OpenFile,Go还提供了一些便捷函数:

使用os.WriteFile覆盖写入

package main

import (
"fmt"
"os"
)

func main() {
content := "这是使用os.WriteFile写入的内容,会覆盖原有内容。\n"
err := os.WriteFile("example.txt", []byte(content), 0644)
if err != nil {
fmt.Println("写入文件失败:", err)
return
}
fmt.Println("文件覆盖写入成功")
}

使用os.ReadFile读取文件

package main

import (
"fmt"
"os"
)

func main() {
data, err := os.ReadFile("example.txt")
if err != nil {
fmt.Println("读取文件失败:", err)
return
}
fmt.Printf("文件内容: %s\n", string(data))
}

综合示例:日志文件操作

package main

import (
"fmt"
"os"
"time"
)

func logMessage(message string) error {
// 以追加模式打开日志文件
file, err := os.OpenFile("app.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
return err
}
defer file.Close()

// 添加时间戳
timestamp := time.Now().Format("2006-01-02 15:04:05")
logEntry := fmt.Sprintf("[%s] %s\n", timestamp, message)

// 写入日志
_, err = file.WriteString(logEntry)
return err
}

func viewLog() error {
// 读取日志文件
data, err := os.ReadFile("app.log")
if err != nil {
return err
}

fmt.Println("=== 应用日志 ===")
fmt.Println(string(data))
return nil
}

func clearLog() error {
// 清空日志文件
file, err := os.OpenFile("app.log", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer file.Close()

_, err = file.WriteString("=== 日志已清空 ===\n")
return err
}

func main() {
// 记录几条日志
logMessage("应用启动")
logMessage("执行操作1")
logMessage("执行操作2")

// 查看日志
viewLog()

// 清空日志
clearLog()

// 记录新日志
logMessage("清空后重新开始记录")

// 再次查看日志
viewLog()
}

Go语言提供了多种文件读写模式,可以根据需求灵活选择:

  1. 只读模式 (os.O_RDONLY):仅读取文件内容
  2. 覆盖写入模式 (os.O_WRONLY|os.O_CREATE|os.O_TRUNC):创建新文件或清空已有文件后写入
  3. 追加模式 (os.O_WRONLY|os.O_CREATE|os.O_APPEND):在文件末尾追加内容
  4. 读写模式 (os.O_RDWR|os.O_CREATE):可读可写,保留原有内容
  5. 读写清空模式 (os.O_RDWR|os.O_CREATE|os.O_TRUNC):清空文件后可读可写
  6. 追加读写模式 (os.O_RDWR|os.O_CREATE|os.O_APPEND):可读可追加
  7. 互斥创建模式 (os.O_WRONLY|os.O_CREATE|os.O_EXCL):确保创建新文件

此外,Go还提供了便捷函数os.WriteFileos.ReadFile,适用于简单的文件读写场景。


Go语言中的文件权限详解:644及其他权限值

在Go语言的文件操作中,文件权限是一个重要的概念。权限值(如0644)决定了谁可以读取、写入或执行文件。本文将详细解释文件权限的含义、各种权限值及其应用场景。

文件权限基础

在Unix/Linux系统中,文件权限分为三类用户:

  1. 所有者(User) - 文件的所有者
  2. 组(Group) - 文件所属的用户组
  3. 其他用户(Other) - 系统中的其他用户

每种用户类型有三种权限:

  1. 读(Read) - 允许读取文件内容
  2. 写(Write) - 允许修改文件内容
  3. 执行(Execute) - 允许执行文件(对于目录,允许访问目录内容)

权限表示方法

八进制表示法

Go语言中使用八进制数表示文件权限,如0644。这个四位数的结构如下:

  • 第一位:特殊权限位(setuid, setgid, sticky)
  • 第二位:所有者权限
  • 第三位:组权限
  • 第四位:其他用户权限

每位权限的值计算方式:

  • 读权限 = 4
  • 写权限 = 2
  • 执行权限 = 1

权限值通过相加组合:

  • 7 = 4+2+1 (读+写+执行)
  • 6 = 4+2 (读+写)
  • 5 = 4+1 (读+执行)
  • 4 = 4 (只读)
  • 3 = 2+1 (写+执行)
  • 2 = 2 (只写)
  • 1 = 1 (只执行)
  • 0 = 0 (无权限)

常见权限值及含义

0644 (rw-r—r—)

  • 所有者:读+写 (6)
  • 组用户:只读 (4)
  • 其他用户:只读 (4)
  • 这是最常见的文件权限,适用于大多数普通文件
// 创建具有0644权限的文件
err := os.WriteFile("example.txt", []byte("内容"), 0644)

0755 (rwxr-xr-x)

  • 所有者:读+写+执行 (7)
  • 组用户:读+执行 (5)
  • 其他用户:读+执行 (5)
  • 适用于可执行文件或目录
// 创建具有0755权限的目录
err := os.Mkdir("mydir", 0755)

0600 (rw———-)

  • 所有者:读+写 (6)
  • 组用户:无权限 (0)
  • 其他用户:无权限 (0)
  • 适用于包含敏感信息的私有文件
// 创建只有所有者可读写的配置文件
file, err := os.OpenFile("config.ini", os.O_CREATE|os.O_WRONLY, 0600)

0777 (rwxrwxrwx)

  • 所有者:读+写+执行 (7)
  • 组用户:读+写+执行 (7)
  • 其他用户:读+写+执行 (7)
  • 所有用户都有完全权限(慎用,有安全风险)
// 创建所有用户都有完全权限的文件(通常不推荐)
err := os.WriteFile("temp.txt", []byte("临时内容"), 0777)

0444 (r—r—r—)

  • 所有者:只读 (4)
  • 组用户:只读 (4)
  • 其他用户:只读 (4)
  • 适用于只读文件,防止意外修改
// 创建只读文件
err := os.WriteFile("readonly.txt", []byte("只读内容"), 0444)

特殊权限位

SetUID (4xxx)

  • 设置用户ID,当执行此文件时,进程的有效用户ID变为文件所有者的用户ID
  • 示例:4755 (rwsr-xr-x)
// 设置SetUID权限(需要超级用户权限)
err := os.Chmod("program", 0755|os.ModeSetuid)

SetGID (2xxx)

  • 设置组ID,当执行此文件时,进程的有效组ID变为文件所属组的组ID
  • 对于目录,新创建的文件会继承目录的组ID
  • 示例:2755 (rwxr-sr-x)
// 设置SetGID权限
err := os.Chmod("program", 0755|os.ModeSetgid)

Sticky Bit (1xxx)

  • 粘滞位,对于目录,只有文件所有者和root用户才能删除目录中的文件
  • 常用于/tmp目录
  • 示例:1755 (rwxr-xr-t)
// 设置Sticky Bit权限
err := os.Chmod("shared_dir", 0755|os.ModeSticky)

使用常量定义权限

Go语言的os包提供了一些常量来表示权限:

const (
ModeDir = fs.ModeDir // d: 目录
ModeAppend = fs.ModeAppend // a: 只能追加
ModeExclusive = fs.ModeExclusive // l: 独占使用
ModeTemporary = fs.ModeTemporary // T: 临时文件
ModeSymlink = fs.ModeSymlink // L: 符号链接
ModeDevice = fs.ModeDevice // D: 设备文件
ModeNamedPipe = fs.ModeNamedPipe // p: 命名管道
ModeSocket = fs.ModeSocket // S: Unix域socket
ModeSetuid = fs.ModeSetuid // u: setuid
ModeSetgid = fs.ModeSetgid // g: setgid
ModeCharDevice = fs.ModeCharDevice // c: 字符设备
ModeSticky = fs.ModeSticky // t: sticky
ModeIrregular = fs.ModeIrregular // ?: 非常规文件

// 权限位
ModePerm = fs.ModePerm // Unix权限位
)

权限操作示例

查看文件权限

package main

import (
"fmt"
"os"
)

func main() {
info, err := os.Stat("example.txt")
if err != nil {
fmt.Println("获取文件信息失败:", err)
return
}

mode := info.Mode()
fmt.Printf("权限八进制表示: %04o\n", mode.Perm())
fmt.Printf("权限字符串表示: %s\n", mode.String())
fmt.Printf("是否是目录: %t\n", mode.IsDir())
fmt.Printf("是否是常规文件: %t\n", mode.IsRegular())
}

修改文件权限

package main

import (
"fmt"
"os"
)

func main() {
// 创建文件
err := os.WriteFile("example.txt", []byte("内容"), 0644)
if err != nil {
fmt.Println("创建文件失败:", err)
return
}

// 修改文件权限为只读
err = os.Chmod("example.txt", 0444)
if err != nil {
fmt.Println("修改权限失败:", err)
return
}
fmt.Println("文件权限已修改为只读")

// 尝试写入文件(应该会失败)
err = os.WriteFile("example.txt", []byte("新内容"), 0644)
if err != nil {
fmt.Println("写入失败(符合预期):", err)
}
}

创建具有特殊权限的文件

package main

import (
"fmt"
"os"
)

func main() {
// 创建具有SetUID权限的可执行文件(需要超级用户权限)
file, err := os.OpenFile("setuid_program", os.O_CREATE|os.O_WRONLY, 0755|os.ModeSetuid)
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
defer file.Close()

// 写入一些内容
_, err = file.WriteString("#!/bin/bash\necho 'SetUID程序'")
if err != nil {
fmt.Println("写入内容失败:", err)
return
}

fmt.Println("SetUID文件创建成功")
}

需要注意的是,文件权限在Windows系统上的行为与Unix/Linux系统有所不同:

  • Windows没有完全相同的权限模型
  • 读写权限会被映射到Windows的文件属性(如只读属性)
  • 执行权限在Windows上主要依赖于文件扩展名(如.exe、.bat等)
  • SetUID、SetGID和Sticky Bit在Windows上无效

Go语言会尽量在不同平台上模拟Unix权限行为,但在编写跨平台应用时应注意这些差异。