文件操作
简介
在 Go 中,文件操作主要依赖以下几个标准库:
os
包:提供了底层的文件操作接口,比如打开、创建、读取、写入、删除文件等。io
包:提供了基本的 I/O 接口,通常与os
配合使用。ioutil
包(Go 1.16 之后推荐使用os
和io
):之前用于简化文件操作,现在功能被分散到其他包中。bufio
包:提供缓冲读写功能,适合处理大文件或需要高效读写的场景。
文件操作的核心是 os.File
类型,它代表一个打开的文件对象,通过它可以执行读取、写入等操作。
创建文件
创建文件可以使用 os
包提供的 Create
函数。
func Create(name string) (*File, error)
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 使用 os 包的 Create 函数创建文件
file, err := os.Create("example.txt")
if err != nil {
fmt.Println("创建文件失败, Error:", err)
return
}
// 输出打印信息
fmt.Println(file.Name(), "文件成功!")
}
打开文件
常见的两种打开文件的方式是使用 os
包提供的两个函数。
Open
函数以只读方式打开文件。
func Open(name string) (*File, error)
OpenFile
函数提供更加灵活的方式打开文件,可以指定打开模式(只读/只写/读写/追加/创建/清空)和权限。
func OpenFile(name string, flag int, perm FileMode) (*File, error)
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 以只读方式打开文件
file1, err := os.Open("example.txt")
if err != nil {
fmt.Println("打开文件失败, Error:", err)
return
}
// 关闭文件
defer file1.Close()
// 输出打印信息
fmt.Println(file1.Name(), "文件打开成功!")
// 以读写方式打开文件
file2, err := os.OpenFile("example.txt", os.O_RDWR, 0666)
if err != nil {
fmt.Println("打开文件失败, Error:", err)
return
}
// 关闭文件
defer file2.Close()
// 输出打印信息
fmt.Println(file2.Name(), "文件打开成功!")
}
写入文件
使用 os.File
结构体提供了几个方法,可以实现文件的写入操作。
Write
方法用于将字节切片写入数据到文件中。
func (f *File) Write(b []byte) (n int, err error)
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 打开文件,指定文件的打开模式为只写和创建,权限为 0666
file, err := os.OpenFile("example.txt", os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println("文件打开失败, Error:", err)
return
}
// 关闭文件
defer file.Close()
// os.File 的 Write 方法用于将字节数组写入文件
n, err := file.Write([]byte("Hello, World!"))
if err != nil {
fmt.Println("字节切片内容写入失败, Error:", err)
return
}
// 输出打印信息
fmt.Println("文件写入成功!写入了", n, "个字节")
}
WriteString
方法用于将字符串写入文件中。
func (f *File) WriteString(s string) (n int, err error)
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 打开文件,指定文件的打开模式为只写和创建,权限为 0666
file, err := os.OpenFile("example.txt", os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println("文件打开失败, Error:", err)
return
}
// 关闭文件
defer file.Close()
// os.File 的 WriteString 方法用于将字符串写入文件
n, err := file.WriteString("Hello, World!")
if err != nil {
fmt.Println("字符串内容写入失败, Error:", err)
return
}
// 输出打印信息
fmt.Println("文件写入成功!写入了", n, "个字节")
}
WriteAt
方法用于从指定位置(偏移量 off
)写入数据到文件中(不移动文件当前的位置指针)。
func (f *File) WriteAt(b []byte, off int64) (n int, err error)
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 打开文件,指定文件的打开模式为只写和创建,权限为 0666
file, err := os.OpenFile("example.txt", os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println("文件打开失败, Error:", err)
return
}
// 关闭文件
file.Close()
// 要写入的数据
data := []byte("Hello, World!")
// 在文件的第3个字节位置写入数据
offset := int64(3)
n, err := file.WriteAt(data, offset)
if err != nil {
fmt.Println("写入文件失败, Error:", err)
return
}
// 输出打印信息
fmt.Printf("成功写入 %d 个字节\n", n)
}
WriteTo
方法用于将当前文件的内容写到另一个 io.Writer
对象中(例如:另一个文件、网络连接、缓冲区等)。
func (f *File) WriteTo(w io.Writer) (n int64, err error)
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 打开一个文件
file1, err := os.Open("file1.txt")
if err != nil {
fmt.Println("文件打开失败, Error:", err)
return
}
// 关闭文件
file1.Close()
// 创建一个新的文件
file2, err := os.Create("file2.txt")
if err != nil {
fmt.Println("文件创建失败, Error:", err)
return
}
// 将file1.txt的内容写入file2.txt
n, err := file1.WriteTo(file2)
if err != nil {
fmt.Println("文件写入失败, Error:", err)
return
}
// 输出打印信息
fmt.Println("将file1.txt的内容写入file2.txt成功,写入了", n, "个字节")
}
读取文件
使用 os.Open
或者 os.OpenFile
函数打开文件后,便可以多文件进行读取操作了,*os.File
结构体提供了几个方法用于读取文件。
首先是 Read
方法从文件中读取数据到字节切片中,返回读取的字节数和错误。
func (f *File) Read(b []byte) (n int, err error)
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 打开文件
file, err := os.Open("example.txt")
if err != nil {
fmt.Println("文件打开失败, Error:", err)
return
}
// 关闭文件
defer file.Close()
// 创建一个长度为 100 的字节切片
buf := make([]byte, 100)
// 从文件中读取数据
n, err := file.Read(buf)
if err != nil {
fmt.Println("文件读取失败, Error:", err)
return
}
// 打印成功读取的字节数
fmt.Println("文件读取成功!读取了", n, "个字节")
// 打印读取到的内容
fmt.Println("读取到的内容:", string(buf[:n]))
}
ReadAt
方法从文件的指定偏移量位置读取数据,不改变文件指针位置。
func (f *File) ReadAt(b []byte, off int64) (n int, err error)
示例:
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开文件
file, err := os.Open("example.txt")
if err != nil {
fmt.Println("文件打开失败, Error:", err)
return
}
// 关闭文件
defer file.Close()
// 创建一个字节切片作为读取的缓冲区,缓冲区大小为15
buf := make([]byte, 15)
// 从第5个字节开始读取
n, err := file.ReadAt(buf, 5)
if err != nil && err != io.EOF {
fmt.Println("文件读取失败, Error:", err)
return
}
// 打印成功读取的字节数
fmt.Printf("从偏移量5读取了 %d 个字节.\n", n)
// 打印读取到的内容
fmt.Printf("读取到的内容:%s\n", string(buf[:n]))
}
Seek
方法用于将文件指针定位到指定的偏移量位置,返回定位后的偏移量和错误信息。
func (f *File) Seek(offset int64, whence int) (int64, error)
示例:
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开文件
file, err := os.Open("example.txt")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
// 关闭文件
defer file.Close()
// 将文件指针移动到第5个字节(从开头算起)
_, err = file.Seek(5, io.SeekStart)
if err != nil {
fmt.Println("Seek 失败:", err)
return
}
// 读取5个字节的内容
buffer := make([]byte, 5)
n, err := file.Read(buffer)
if err != nil {
fmt.Println("读取失败:", err)
return
}
// 打印成功读取的字节数
fmt.Printf("读取到的内容: %s\n", buffer[:n])
}
获取文件信息
Stat
方法用于获取文件的信息,返回文件信息和错误信息。
func Stat(name string) (fi FileInfo, err error)
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 打开文件
file, err := os.Open("example.txt")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
// 关闭文件
defer file.Close()
// 获取文件信息
fileInfo, err := file.Stat()
fmt.Println("文件名:", fileInfo.Name())
fmt.Println("文件大小:", fileInfo.Size())
fmt.Println("文件权限:", fileInfo.Mode())
fmt.Println("文件修改时间:", fileInfo.ModTime())
fmt.Println("文件是否是目录:", fileInfo.IsDir())
fmt.Println("文件是否是文件:", fileInfo.Mode().IsRegular())
}
文件重命名
Rename
方法用于将文件从一个路径重命名到另一个路径,返回错误信息。
func Rename(oldpath, newpath string) error
示例:
package main
import (
"os"
"fmt"
)
func main() {
// 重命名文件
err := os.Rename("example.txt", "example-new.txt")
if err != nil {
fmt.Println("文件重命名失败:", err)
return
}
// 输出打印信息
fmt.Println("文件重命名成功!")
}
删除文件
Remove
方法用于删除文件,返回错误信息。
func Remove(name string) error
示例:
package main
import (
"os"
"fmt"
)
func main() {
// 删除文件
err := os.Remove("example.txt")
if err != nil {
fmt.Println("文件删除失败:", err)
return
}
// 输出打印信息
fmt.Println("文件删除成功!")
}
文件复制
Copy
方法用于复制文件,返回错误信息。
func Copy(dstName, srcName string) error
示例:
package main
import (
"os"
"fmt"
)
func main() {
// 复制文件
err := os.Copy("example.txt", "example-copy.txt")
if err != nil {
fmt.Println("文件复制失败:", err)
return
}
// 输出打印信息
fmt.Println("文件复制成功!")
}
文件夹
创建
Mkdir
方法用于创建文件夹,返回错误信息。
func Mkdir(name string, perm os.FileMode) error
MkdirAll
方法用于递归创建文件夹,返回错误信息。
func MkdirAll(path string, perm os.FileMode) error
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 创建文件夹
err := os.Mkdir("a", 0755)
if err != nil {
fmt.Println("文件夹创建失败:", err)
return
}
fmt.Println("文件夹创建成功!")
// 创建多层级文件夹
err = os.MkdirAll("./a/b/c", 0755)
if err != nil {
fmt.Println("多层级文件夹创建失败:", err)
return
}
fmt.Println("多层级文件夹创建成功!")
}
读取
ReadDir
方法用于读取文件夹,返回文件夹信息和错误信息。
func ReadDir(name string) ([]FileInfo, error)
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 指定要读取文件夹的路径
dirPath := "./testdir"
// 读取目录内容
entries, err := os.ReadDir(dirPath)
if err != nil {
fmt.Println("读取目录失败:", err)
return
}
// 遍历目录条目
fmt.Println("目录内容:")
for i, entry := range entries {
// 获取条目名称和类型
name := entry.Name()
isDir := entry.IsDir()
fmt.Printf("%d. %s (%s)\n", i+1, name, map[bool]string{true: "目录", false: "文件"}[isDir])
}
}
Walk
方法用于递归遍历文件夹,返回错误信息。
func Walk(dir string, fn filepath.WalkFunc) error
示例:
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
// 递归读取目录
// 指定要读取的目录
dirPath := "./testdir"
// 递归遍历目录
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err // 如果出错,返回错误
}
// 打印路径和类型
typeStr := "文件"
if info.IsDir() {
typeStr = "目录"
}
fmt.Printf("%s (%s)\n", path, typeStr)
return nil
})
if err != nil {
fmt.Println("遍历目录失败:", err)
return
}
}
删除
Remove
方法用于单个空目录或文件,返回错误信息。
func Remove(name string) error
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 指定要删除的空目录
dirPath := "emptydir"
// 创建一个空目录用于测试
err := os.Mkdir(dirPath, 0755)
if err != nil {
fmt.Println("创建目录失败:", err)
return
}
// 删除空目录
err = os.Remove(dirPath)
if err != nil {
fmt.Println("删除目录失败:", err)
return
}
fmt.Println("空目录删除成功!")
}
RemoveAll
方法用于递归删除文件夹及其所有内容(类似 rm -r),返回错误信息。
func RemoveAll(path string) error
示例:
package main
import (
"fmt"
"os"
)
func main() {
// 指定要删除的目录
dirPath := "testdir"
// 创建测试目录和内容
err := os.MkdirAll(dirPath+"/subdir", 0755)
if err != nil {
fmt.Println("创建目录失败:", err)
return
}
err = os.WriteFile(dirPath+"/file1.txt", []byte("Hello"), 0644)
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
// 递归删除目录及其内容
err = os.RemoveAll(dirPath)
if err != nil {
fmt.Println("删除目录失败:", err)
return
}
fmt.Println("目录及其内容删除成功!")
}
复制
在 Go 语言中,标准库没有直接提供“文件夹复制”的函数,可以编写一个函数递归遍历整个文件夹,然后递归复制每个文件和子文件夹。
一个简单的文件夹复制的代码示例如下。
package main
import (
"fmt"
"io"
"os"
"path/filepath"
)
func copyDir(src, dst string) error {
// 确保源路径存在且是目录
srcInfo, err := os.Stat(src)
if err != nil {
return fmt.Errorf("源路径错误: %v", err)
}
if !srcInfo.IsDir() {
return fmt.Errorf("源路径不是目录: %s", src)
}
// 创建目标目录
err = os.MkdirAll(dst, srcInfo.Mode())
if err != nil {
return fmt.Errorf("创建目标目录失败: %v", err)
}
// 遍历源目录
err = filepath.Walk(src, func(srcPath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 计算目标路径
relPath, err := filepath.Rel(src, srcPath)
if err != nil {
return err
}
dstPath := filepath.Join(dst, relPath)
// 如果是目录,创建目录
if info.IsDir() {
return os.MkdirAll(dstPath, info.Mode())
}
// 如果是文件,复制文件内容
return copyFile(srcPath, dstPath)
})
return err
}
func copyFile(src, dst string) error {
// 打开源文件
srcFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("打开源文件失败: %v", err)
}
defer srcFile.Close()
// 创建目标文件
dstFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("创建目标文件失败: %v", err)
}
defer dstFile.Close()
// 复制文件内容
_, err = io.Copy(dstFile, srcFile)
if err != nil {
return fmt.Errorf("复制文件内容失败: %v", err)
}
// 同步文件权限
srcInfo, err := os.Stat(src)
if err != nil {
return err
}
return os.Chmod(dst, srcInfo.Mode())
}
func main() {
// 定义源目录和目标目录
srcDir := "source"
dstDir := "destination"
// 创建测试目录和文件
err := os.MkdirAll(srcDir+"/subdir", 0755)
if err != nil {
fmt.Println("创建源目录失败:", err)
return
}
err = os.WriteFile(srcDir+"/file1.txt", []byte("Hello, World!"), 0644)
if err != nil {
fmt.Println("创建源文件失败:", err)
return
}
// 执行复制
err = copyDir(srcDir, dstDir)
if err != nil {
fmt.Println("复制文件夹失败:", err)
return
}
fmt.Println("文件夹复制成功!")
}