Go语言文件操作完整指南
ioutil库的替代方案
Go 1.16开始,ioutil
包被弃用,其功能被迁移到以下包:
原ioutil函数 | 新位置 | 说明 |
---|---|---|
ioutil.ReadFile() | os.ReadFile() | 读取整个文件 |
ioutil.WriteFile() | os.WriteFile() | 写入文件 |
ioutil.ReadDir() | os.ReadDir() | 读取目录 |
ioutil.ReadAll() | io.ReadAll() | 读取所有数据 |
ioutil.TempDir() | os.MkdirTemp() | 创建临时目录 |
ioutil.TempFile() | os.CreateTemp() | 创建临时文件 |
1. 基础文件读写操作
1.1 读取整个文件
package main
import (
"fmt"
"os"
)
func main() {
// 新方式:使用 os.ReadFile
content, err := os.ReadFile("example.txt")
if err != nil {
fmt.Printf("读取文件失败: %v\n", err)
return
}
fmt.Printf("文件内容: %s\n", content)
}
1.2 写入文件
package main
import (
"fmt"
"os"
)
func main() {
data := []byte("Hello, Go文件操作!")
// 新方式:使用 os.WriteFile
err := os.WriteFile("output.txt", data, 0644)
if err != nil {
fmt.Printf("写入文件失败: %v\n", err)
return
}
fmt.Println("文件写入成功")
}
2. 文件打开和关闭
2.1 基本文件操作
package main
import (
"fmt"
"os"
)
func main() {
// 打开文件
file, err := os.Open("example.txt")
if err != nil {
fmt.Printf("打开文件失败: %v\n", err)
return
}
defer file.Close() // 确保文件被关闭
// 获取文件信息
fileInfo, err := file.Stat()
if err != nil {
fmt.Printf("获取文件信息失败: %v\n", err)
return
}
fmt.Printf("文件名: %s\n", fileInfo.Name())
fmt.Printf("文件大小: %d 字节\n", fileInfo.Size())
fmt.Printf("修改时间: %v\n", fileInfo.ModTime())
}
2.2 创建和写入文件
package main
import (
"fmt"
"os"
)
func main() {
// 创建文件(如果存在会截断)
file, err := os.Create("newfile.txt")
if err != nil {
fmt.Printf("创建文件失败: %v\n", err)
return
}
defer file.Close()
// 写入数据
data := "这是新创建的文件内容\n"
_, err = file.WriteString(data)
if err != nil {
fmt.Printf("写入失败: %v\n", err)
return
}
fmt.Println("文件创建并写入成功")
}
3. 按行读取文件
3.1 使用bufio包逐行读取
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.Open("example.txt")
if err != nil {
fmt.Printf("打开文件失败: %v\n", err)
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
lineNum := 1
for scanner.Scan() {
fmt.Printf("第%d行: %s\n", lineNum, scanner.Text())
lineNum++
}
if err := scanner.Err(); err != nil {
fmt.Printf("读取文件时出错: %v\n", err)
}
}
3.2 使用bufio.Reader
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
file, err := os.Open("example.txt")
if err != nil {
fmt.Printf("打开文件失败: %v\n", err)
return
}
defer file.Close()
reader := bufio.NewReader(file)
lineNum := 1
for {
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
if len(line) > 0 {
fmt.Printf("第%d行: %s", lineNum, line)
}
break
}
fmt.Printf("读取错误: %v\n", err)
break
}
fmt.Printf("第%d行: %s", lineNum, line)
lineNum++
}
}
4. 文件追加操作
package main
import (
"fmt"
"os"
)
func main() {
// 以追加模式打开文件
file, err := os.OpenFile("append.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("打开文件失败: %v\n", err)
return
}
defer file.Close()
// 追加内容
content := "这是追加的内容\n"
_, err = file.WriteString(content)
if err != nil {
fmt.Printf("写入失败: %v\n", err)
return
}
fmt.Println("内容追加成功")
}
5. 目录操作
5.1 读取目录
package main
import (
"fmt"
"os"
)
func main() {
// 新方式:使用 os.ReadDir
entries, err := os.ReadDir(".")
if err != nil {
fmt.Printf("读取目录失败: %v\n", err)
return
}
fmt.Println("当前目录内容:")
for _, entry := range entries {
if entry.IsDir() {
fmt.Printf("[目录] %s\n", entry.Name())
} else {
fmt.Printf("[文件] %s\n", entry.Name())
}
}
}
5.2 创建目录
package main
import (
"fmt"
"os"
)
func main() {
// 创建单个目录
err := os.Mkdir("testdir", 0755)
if err != nil {
fmt.Printf("创建目录失败: %v\n", err)
} else {
fmt.Println("目录创建成功")
}
// 创建多级目录
err = os.MkdirAll("path/to/nested/dir", 0755)
if err != nil {
fmt.Printf("创建多级目录失败: %v\n", err)
} else {
fmt.Println("多级目录创建成功")
}
}
6. 文件和目录的判断
package main
import (
"fmt"
"os"
)
func main() {
path := "example.txt"
// 检查文件或目录是否存在
if _, err := os.Stat(path); err == nil {
fmt.Printf("%s 存在\n", path)
// 获取详细信息
info, _ := os.Stat(path)
if info.IsDir() {
fmt.Printf("%s 是目录\n", path)
} else {
fmt.Printf("%s 是文件,大小: %d 字节\n", path, info.Size())
}
} else if os.IsNotExist(err) {
fmt.Printf("%s 不存在\n", path)
} else {
fmt.Printf("检查 %s 时出错: %v\n", path, err)
}
}
7. 临时文件和目录
7.1 创建临时文件
package main
import (
"fmt"
"os"
)
func main() {
// 新方式:使用 os.CreateTemp
tmpFile, err := os.CreateTemp("", "example_*.txt")
if err != nil {
fmt.Printf("创建临时文件失败: %v\n", err)
return
}
defer os.Remove(tmpFile.Name()) // 清理临时文件
defer tmpFile.Close()
fmt.Printf("临时文件路径: %s\n", tmpFile.Name())
// 写入临时文件
content := "这是临时文件的内容"
_, err = tmpFile.WriteString(content)
if err != nil {
fmt.Printf("写入临时文件失败: %v\n", err)
return
}
fmt.Println("临时文件创建并写入成功")
}
7.2 创建临时目录
package main
import (
"fmt"
"os"
)
func main() {
// 新方式:使用 os.MkdirTemp
tmpDir, err := os.MkdirTemp("", "example_dir_*")
if err != nil {
fmt.Printf("创建临时目录失败: %v\n", err)
return
}
defer os.RemoveAll(tmpDir) // 清理临时目录
fmt.Printf("临时目录路径: %s\n", tmpDir)
}
8. 文件复制
package main
import (
"fmt"
"io"
"os"
)
func copyFile(src, dst string) error {
sourceFile, err := os.Open(src)
if err != nil {
return err
}
defer sourceFile.Close()
destFile, err := os.Create(dst)
if err != nil {
return err
}
defer destFile.Close()
_, err = io.Copy(destFile, sourceFile)
return err
}
func main() {
err := copyFile("source.txt", "destination.txt")
if err != nil {
fmt.Printf("文件复制失败: %v\n", err)
} else {
fmt.Println("文件复制成功")
}
}
9. 文件权限操作
package main
import (
"fmt"
"os"
)
func main() {
filename := "example.txt"
// 修改文件权限
err := os.Chmod(filename, 0755)
if err != nil {
fmt.Printf("修改权限失败: %v\n", err)
return
}
// 获取文件信息查看权限
info, err := os.Stat(filename)
if err != nil {
fmt.Printf("获取文件信息失败: %v\n", err)
return
}
fmt.Printf("文件权限: %v\n", info.Mode().Perm())
}
10. 文件删除和重命名
package main
import (
"fmt"
"os"
)
func main() {
// 重命名文件
err := os.Rename("oldname.txt", "newname.txt")
if err != nil {
fmt.Printf("重命名失败: %v\n", err)
} else {
fmt.Println("文件重命名成功")
}
// 删除文件
err = os.Remove("unwanted.txt")
if err != nil {
fmt.Printf("删除文件失败: %v\n", err)
} else {
fmt.Println("文件删除成功")
}
// 删除目录(包括所有内容)
err = os.RemoveAll("unwanted_dir")
if err != nil {
fmt.Printf("删除目录失败: %v\n", err)
} else {
fmt.Println("目录删除成功")
}
}
11. 文件路径操作
package main
import (
"fmt"
"path/filepath"
)
func main() {
path := "/home/user/documents/file.txt"
fmt.Printf("完整路径: %s\n", path)
fmt.Printf("目录: %s\n", filepath.Dir(path))
fmt.Printf("文件名: %s\n", filepath.Base(path))
fmt.Printf("扩展名: %s\n", filepath.Ext(path))
// 构建路径
newPath := filepath.Join("home", "user", "documents", "newfile.txt")
fmt.Printf("构建的路径: %s\n", newPath)
// 获取绝对路径
absPath, err := filepath.Abs("./example.txt")
if err == nil {
fmt.Printf("绝对路径: %s\n", absPath)
}
}
12. 错误处理最佳实践
package main
import (
"errors"
"fmt"
"os"
)
func safeFileOperation(filename string) error {
// 检查文件是否存在
if _, err := os.Stat(filename); os.IsNotExist(err) {
return fmt.Errorf("文件 %s 不存在", filename)
}
// 打开文件
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("无法打开文件 %s: %w", filename, err)
}
defer file.Close()
// 读取文件
content, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("读取文件 %s 失败: %w", filename, err)
}
fmt.Printf("成功读取文件,大小: %d 字节\n", len(content))
return nil
}
func main() {
if err := safeFileOperation("example.txt"); err != nil {
fmt.Printf("操作失败: %v\n", err)
// 检查特定错误类型
if errors.Is(err, os.ErrNotExist) {
fmt.Println("这是一个文件不存在的错误")
}
}
}
总结
主要变化点:
ioutil.ReadFile()
→os.ReadFile()
ioutil.WriteFile()
→os.WriteFile()
ioutil.ReadDir()
→os.ReadDir()
ioutil.ReadAll()
→io.ReadAll()
ioutil.TempDir()
→os.MkdirTemp()
ioutil.TempFile()
→os.CreateTemp()
这些新的API提供了更好的性能和更清晰的包结构。建议在新项目中直接使用新的API,旧项目可以逐步迁移。