文章目录
文件操作
基本介绍
基本介绍
- 文件操作是指对计算机文件进行读取、写入、修改、删除和移动等操作的过程,它可以用于读取配置文件、存储日志、处理用户上传的文件等,Go中主要通过os和bufio包提供文件操作功能。
- 文件在程序中是以流的形式进行操作的,我们把数据在数据源(文件)和程序(内存)之间经历的路径叫做流。其中数据从数据源到程序的路径叫做输入流,数据从程序到数据源的路径叫做输出流。
文件流示意图如下:
普通的文件操作方式(os包)
os包介绍
在os包中,File类型代表一个打开的文件,其封装了与文件相关的操作和属性。File结构体的定义如下:
type File struct {
*file // os specific
}
File结构体中以*type
的方式嵌套了file类型的匿名结构体指针,实际文件的属性信息都存储在file结构体中。file结构体的定义如下:
type file struct {
pfd poll.FD
name string
dirinfo atomic.Pointer[dirInfo] // nil unless directory being read
nonblock bool // whether we set nonblocking mode
stdoutOrErr bool // whether this is stdout or stderr
appendMode bool // whether file is opened for appending
}
file结构体各字段说明:
- pfd:用于与底层的操作系统文件描述符进行交互。
- name:表示文件的名称(包括路径)。
- dirinfo:用于在读取目录时缓存目录的信息(打开的文件是目录时被使用)。
- nonblock:表示文件是否设置为非阻塞模式。
- stdoutOrErr:表示文件是否是标准输出或标准错误。
- appendMode:表示文件是否以追加模式打开。
每一个打开的文件都对应一个文件描述符,file结构体中的pfd是poll.FD类型的,实际文件对应的文件描述符就存储在poll.FD结构体的Sysfd字段中。FD结构体的定义如下:
type FD struct {
// Lock sysfd and serialize access to Read and Write methods.
fdmu fdMutex
// System file descriptor. Immutable until Close.
Sysfd int
// Platform dependent state of the file descriptor.
SysFile
// I/O poller.
pd pollDesc
// Semaphore signaled when file is closed.
csema uint32
// Non-zero if this file has been set to blocking mode.
isBlocking uint32
// Whether this is a streaming descriptor, as opposed to a
// packet-based descriptor like a UDP socket. Immutable.
IsStream bool
// Whether a zero byte read indicates EOF. This is false for a
// message based socket connection.
ZeroReadIsEOF bool
// Whether this is a file rather than a network socket.
isFile bool
}
打开文件
在os包中,使用OpenFile函数打开文件,该函数的函数原型如下:
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
参数说明:
- name:表示需要打开的文件名称(包括路径)。
- flag:表示打开文件的方式。
- perm:表示新创建文件的权限,通常设置为0666(表示任何人都可读写,不可执行)。
返回值说明:
- file:如果打开文件成功,将返回文件对应的File结构体。
- err:如果打开文件过程中出错,将返回非nil的错误值。
打开文件的方式可以使用以下标注之一或它们的组合。如下:
参数选项 | 含义 |
---|---|
O_RDONLY | 以只读方式打开文件 |
O_WRONLY | 以只写方式打开文件 |
O_RDWR | 以读写方式打开文件 |
O_APPEND | 以追加的方式打开文件 |
O_CREATE | 如果文件不存在,则创建文件 |
O_EXCL | 与O_CREATE一起使用,确保创建新文件时不会覆盖现有文件 |
O_SYNC | 在每次写入操作后同步文件内容到磁盘 |
O_TRUNC | 如果文件已存在,将截断文件为零长度 |
打开文件示例如下:
package main
import (
"fmt"
"os"
)
func main() {
name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\NormalOperation\data.txt`
// 打开文件
file, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Printf("open file error, err = %v\n", err)
return
}
fmt.Printf("open file success, fd = %v\n", file.Fd()) // open file success, fd = 420
}
说明一下:
- 通过File结构体的Fd方法,可以获取该文件对应的文件描述符。文件的文件描述符由底层操作系统分配,每次打开文件时分配的文件描述符可能不同。
关闭文件
在os包中,使用File结构体的Close方法关闭文件,该方法的原型如下:
func (f *File) Close() error
返回值说明:
- 关闭文件成功返回nil,否则返回非nil的错误值。
关闭文件示例如下:
package main
import (
"fmt"
"os"
)
func main() {
name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\NormalOperation\data.txt`
// 1、打开文件
file, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Printf("open file error, err = %v\n", err)
return
}
// 2、延迟关闭文件
defer file.Close()
}
说明一下:
- 文件操作完毕后需要及时调用Close方法对文件进行关闭,避免造成文件描述符泄露。
- 通常利用defer机制对文件进行延迟关闭,在defer语句之后仍然可以操作文件,文件将会在函数执行完毕后自动关闭。
获取文件属性信息
在os包中,使用File结构体的Stat方法获取文件的属性信息,该方法的原型如下:
func (f *File) Stat() (fi FileInfo, err error)
返回值说明:
- fi:如果方法调用成功,将返回文件的属性信息。
- err:如果方法调用过程中出错,将返回非nil的错误值。
Stat方法获取到的文件信息FileInfo是一个接口类型,该类型的定义如下:
type FileInfo interface {
Name() string // base name of the file
Size() int64 // length in bytes for regular files; system-dependent for others
Mode() FileMode // file mode bits
ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
Sys() any // underlying data source (can return nil)
}
FileInfo接口中各方法说明:
- Name方法:返回文件的基本名称(不包含路径)。
- Size方法:返回文件的大小。
- Mode方法:返回文件的权限和模式位信息。
- ModTime方法:返回文件最后一次修改时间。
- IsDir方法:判断文件是否是一个目录。
- Sys方法:返回底层数据源,通常是操作系统特定的文件信息(可能返回nil)。
获取文件属性信息示例如下:
package main
import (
"fmt"
"os"
)
func main() {
name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\NormalOperation\data.txt`
// 1、打开文件
file, err := os.OpenFile(name, os.O_RDONLY, 0666)
if err != nil {
if os.IsNotExist(err) {
fmt.Println("warning: file not exists...")
} else {
fmt.Printf("open file error, err = %v\n", err)