Go 语言文件处理
在 Go 语言中,文件处理是一个非常重要的功能,它允许我们读取、写入和操作文件。无论是处理配置文件、日志文件,还是进行数据持久化,文件处理都是不可或缺的一部分。
Go 语言提供了丰富的标准库来支持文件处理,包括文件的打开、关闭、读取、写入、追加和删除等操作。
-
os是核心库 :提供底层文件操作(创建、读写、删除等),大多数场景优先使用。 -
io提供通用接口 :如Reader/Writer,可与文件、网络等数据源交互。 -
bufio优化性能 :通过缓冲减少 I/O 操作次数,适合频繁读写。 -
ioutil已弃用 :Go 1.16 后其功能迁移到os和io包。 -
path/filepath处理路径 :跨平台兼容(Windows/Unix 路径分隔符差异)。
| 库名 | 主要方法/函数 | 用途说明 | 示例代码 |
|---|---|---|---|
os
|
Create(name string) (*File, error)
|
创建文件(若存在则清空) |
file, err := os.Create("test.txt")
|
Open(name string) (*File, error)
|
只读方式打开文件 |
file, err := os.Open("data.txt")
|
|
OpenFile(name string, flag int, perm FileMode) (*File, error)
|
自定义模式打开文件(可指定读写、追加等) |
file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_WRONLY, 0644)
|
|
ReadFile(name string) ([]byte, error)
|
一次性读取整个文件内容(小文件适用) |
data, err := os.ReadFile("config.json")
|
|
WriteFile(name string, data []byte, perm FileMode) error
|
一次性写入文件(覆盖原有内容) |
err := os.WriteFile("out.txt", []byte("Hello"), 0644)
|
|
Remove(name string) error
|
删除文件或空目录 |
err := os.Remove("temp.txt")
|
|
Rename(oldpath, newpath string) error
|
重命名或移动文件 |
err := os.Rename("old.txt", "new.txt")
|
|
Stat(name string) (FileInfo, error)
|
获取文件信息(大小、权限等) |
info, err := os.Stat("file.txt")
|
|
Mkdir(name string, perm FileMode) error
|
创建单个目录 |
err := os.Mkdir("mydir", 0755)
|
|
MkdirAll(path string, perm FileMode) error
|
递归创建多级目录 |
err := os.MkdirAll("path/to/dir", 0755)
|
|
ReadDir(name string) ([]DirEntry, error)
|
读取目录内容 |
entries, err := os.ReadDir(".")
|
|
io
|
Copy(dst Writer, src Reader) (written int64, err error)
|
从
Reader
复制数据到
Writer
(如文件复制)
|
io.Copy(dstFile, srcFile)
|
ReadAll(r Reader) ([]byte, error)
|
从
Reader
读取所有数据(类似
os.ReadFile
,但针对接口)
|
data, err := io.ReadAll(file)
|
|
bufio
|
NewScanner(r Reader) *Scanner
|
创建逐行扫描器(适合逐行读取) |
scanner := bufio.NewScanner(file)
|
NewReader(rd io.Reader) *Reader
|
创建带缓冲的读取器(提高大文件读取效率) |
reader := bufio.NewReader(file)
|
|
NewWriter(w io.Writer) *Writer
|
创建带缓冲的写入器(提高写入效率) |
writer := bufio.NewWriter(file)
|
|
ioutil
|
ReadFile(filename string) ([]byte, error)
|
(已弃用,推荐
os.ReadFile
)
|
data, err := ioutil.ReadFile("old.txt")
|
WriteFile(filename string, data []byte, perm os.FileMode) error
|
(已弃用,推荐
os.WriteFile
)
|
err := ioutil.WriteFile("out.txt", data, 0644)
|
|
TempDir(dir, pattern string) (name string, err error)
|
(已弃用,推荐
os.MkdirTemp
)
|
dir, err := ioutil.TempDir("", "tmp")
|
|
TempFile(dir, pattern string) (f *os.File, err error)
|
(已弃用,推荐
os.CreateTemp
)
|
file, err := ioutil.TempFile("", "temp-*")
|
|
path/filepath
|
Join(elem ...string) string
|
跨平台安全的路径拼接 |
path := filepath.Join("dir", "file.txt")
|
Walk(root string, fn WalkFunc) error
|
递归遍历目录树 |
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {...})
|
|
Abs(path string) (string, error)
|
获取绝对路径 |
absPath, err := filepath.Abs("file.txt")
|
不同场景推荐使用方法
| 场景 | 推荐方法 | 原因 |
|---|---|---|
| 读取小文件 |
os.ReadFile("file.txt")
|
简洁高效,自动处理打开/关闭 |
| 逐行读取大文件 |
bufio.NewScanner(file)
|
内存友好,逐行处理 |
| 高效写入大量数据 |
bufio.NewWriter(file)
+
writer.WriteString()
|
缓冲减少磁盘 I/O 次数 |
| 递归遍历目录 |
filepath.Walk("/path", callback)
|
自动处理子目录和错误 |
| 跨平台路径拼接 |
filepath.Join("dir", "file.txt")
|
自动处理不同操作系统的路径分隔符(
/
或
\
)
|
文件创建
在 Go 语言中,我们使用
os
包来创建文件。
os.Create
函数用于创建一个文件,并返回一个
*os.File
类型的文件对象。创建文件后,我们通常需要调用
Close
方法来关闭文件,以释放系统资源。
packagemainimport("log""os")funcmain(){// 创建文件,如果文件已存在会被截断(清空)file,err:=os.Create("test.txt")iferr!=nil{log.Fatal(err)}deferfile.Close()// 确保文件关闭log.Println("文件创建成功")}
文件的打开与关闭
在 Go 语言中,我们使用
os
包来打开和关闭文件。
os.Open
函数用于打开一个文件,并返回一个
*os.File
类型的文件对象。打开文件后,我们通常需要调用
Close
方法来关闭文件,以释放系统资源。
打开文件
packagemainimport("fmt""os")funcmain(){file,err:=os.Open("example.txt")iferr!=nil{fmt.Println("Error opening file:",err)return}deferfile.Close()fmt.Println("File opened successfully!")}
在上面的代码中,我们使用
os.Open
打开了一个名为
example.txt
的文件。如果文件打开失败,程序会打印错误信息并退出。
defer file.Close()
确保在函数返回前关闭文件。
关闭文件是一个重要的步骤,它可以防止文件描述符泄漏。在 Go 中,我们通常使用
defer
语句来确保文件在函数结束时被关闭。
文件的读取
Go 语言提供了多种读取文件的方式,包括逐行读取、一次性读取整个文件等。我们可以使用
bufio
包来逐行读取文件,或者使用
ioutil
包来一次性读取整个文件。
逐行读取文件
packagemainimport("bufio""fmt""os")funcmain(){file,err:=os.Open("example.txt")iferr!=nil{fmt.Println("Error opening file:",err)return}deferfile.Close()scanner:=bufio.NewScanner(file)forscanner.Scan(){fmt.Println(scanner.Text())}iferr:=scanner.Err();err!=nil{fmt.Println("Error reading file:",err)}}
在上面的代码中,我们使用
bufio.NewScanner
创建了一个扫描器,然后通过
scanner.Scan()
逐行读取文件内容,并使用
scanner.Text()
获取每一行的文本。
一次性读取整个文件
packagemainimport("fmt""io/ioutil")funcmain(){content,err:=ioutil.ReadFile("example.txt")iferr!=nil{fmt.Println("Error reading file:",err)return}fmt.Println(string(content))}
在这个例子中,我们使用
ioutil.ReadFile
一次性读取整个文件的内容,并将其转换为字符串打印出来。
文件的写入
Go 语言也提供了多种写入文件的方式,包括逐行写入、一次性写入等。我们可以使用
os
包来创建和写入文件。
packagemainimport("log""os")funcmain(){// 方式1:直接写入字符串file,err:=os.Create("write1.txt")iferr!=nil{log.Fatal(err)}deferfile.Close()file.WriteString("直接写入字符串\n")// 方式2:写入字节切片data:=[]byte("写入字节切片\n")file.Write(data)// 方式3:使用fmt.Fprintf格式化写入fmt.Fprintf(file,"格式化写入: %d\n",123)}
逐行写入文件
packagemainimport("bufio""fmt""os")funcmain(){file,err:=os.Create("output.txt")iferr!=nil{fmt.Println("Error creating file:",err)return}deferfile.Close()writer:=bufio.NewWriter(file)fmt.Fprintln(writer,"Hello, World!")writer.Flush()}
在这个例子中,我们使用
os.Create
创建了一个名为
output.txt
的文件,并使用
bufio.NewWriter
创建一个写入器。然后,我们使用
fmt.Fprintln
将字符串写入文件,并调用
writer.Flush()
确保所有数据都被写入文件。
一次性写入文件
packagemainimport("fmt""io/ioutil")funcmain(){content:=[]byte("Hello, World!")err:=ioutil.WriteFile("output.txt",content,0644)iferr!=nil{fmt.Println("Error writing file:",err)return}fmt.Println("File written successfully!")}
在这个例子中,我们使用
ioutil.WriteFile
一次性将字节数组写入文件。
0644
是文件的权限模式,表示文件所有者可以读写,其他用户只能读取。
文件的追加写入
有时候我们需要在文件的末尾追加内容,而不是覆盖原有内容。Go 语言提供了
os.OpenFile
函数来实现这一功能。
packagemainimport("fmt""os")funcmain(){file,err:=os.OpenFile("output.txt",os.O_APPEND|os.O_WRONLY,0644)iferr!=nil{fmt.Println("Error opening file:",err)return}deferfile.Close()if_,err:=file.WriteString("Appended text\n");err!=nil{fmt.Println("Error appending to file:",err)return}fmt.Println("Text appended successfully!")}
在这个例子中,我们使用
os.OpenFile
打开文件,并指定
os.O_APPEND
标志来在文件末尾追加内容。然后,我们使用
file.WriteString
将字符串追加到文件中。
文件的删除
在 Go 语言中,我们可以使用
os.Remove
函数来删除文件。
packagemainimport("fmt""os")funcmain(){err:=os.Remove("output.txt")iferr!=nil{fmt.Println("Error deleting file:",err)return}fmt.Println("File deleted successfully!")}
在这个例子中,我们使用
os.Remove
删除了名为
output.txt
的文件。如果文件删除失败,程序会打印错误信息。
文件信息与操作
获取文件信息
packagemainimport("fmt""log""os")funcmain(){fileInfo,err:=os.Stat("test.txt")iferr!=nil{log.Fatal(err)}fmt.Println("文件名:",fileInfo.Name())fmt.Println("文件大小:",fileInfo.Size(),"字节")fmt.Println("权限:",fileInfo.Mode())fmt.Println("最后修改时间:",fileInfo.ModTime())fmt.Println("是目录吗:",fileInfo.IsDir())}
检查文件是否存在
import("fmt""os")funcmain(){if_,err:=os.Stat("test.txt");os.IsNotExist(err){fmt.Println("文件不存在")}else{fmt.Println("文件存在")}}
重命名和移动文件
packagemainimport("log""os")funcmain(){err:=os.Rename("old.txt","new.txt")iferr!=nil{log.Fatal(err)}log.Println("重命名成功")}
目录操作
创建目录
packagemainimport("log""os")funcmain(){// 创建单个目录err:=os.Mkdir("newdir",0755)iferr!=nil{log.Fatal(err)}// 递归创建多级目录err=os.MkdirAll("path/to/newdir",0755)iferr!=nil{log.Fatal(err)}}
读取目录内容
packagemainimport("fmt""log""os")funcmain(){entries,err:=os.ReadDir(".")iferr!=nil{log.Fatal(err)}for_,entry:=rangeentries{info,_:=entry.Info()fmt.Printf("%-20s %8d %v\n",entry.Name(),info.Size(),info.ModTime().Format("2006-01-02 15:04:05"))}}
删除目录
packagemainimport("log""os")funcmain(){// 删除空目录err:=os.Remove("emptydir")iferr!=nil{log.Fatal(err)}// 递归删除目录及其内容err=os.RemoveAll("path/to/dir")iferr!=nil{log.Fatal(err)}}
高级文件操作
文件复制
packagemainimport("io""log""os")funcmain(){srcFile,err:=os.Open("source.txt")iferr!=nil{log.Fatal(err)}defersrcFile.Close()dstFile,err:=os.Create("destination.txt")iferr!=nil{log.Fatal(err)}deferdstFile.Close()bytesCopied,err:=io.Copy(dstFile,srcFile)iferr!=nil{log.Fatal(err)}log.Printf("复制完成,共复制 %d 字节",bytesCopied)}
文件追加
packagemainimport("log""os")funcmain(){file,err:=os.OpenFile("log.txt",os.O_APPEND|os.O_CREATE|os.O_WRONLY,0644)iferr!=nil{log.Fatal(err)}deferfile.Close()if_,err:=file.WriteString("新的日志内容\n");err!=nil{log.Fatal(err)}}
临时文件和目录
packagemainimport("fmt""log""os")funcmain(){// 创建临时文件tmpFile,err:=os.CreateTemp("","example-*.txt")iferr!=nil{log.Fatal(err)}deferos.Remove(tmpFile.Name())// 清理fmt.Println("临时文件:",tmpFile.Name())// 创建临时目录tmpDir,err:=os.MkdirTemp("","example-*")iferr!=nil{log.Fatal(err)}deferos.RemoveAll(tmpDir)// 清理fmt.Println("临时目录:",tmpDir)}