一、判断文件是否存在
Golang判断文件是否存在,跨平台实现方案如下:
func Exists(filename string) bool {
stat, err := os.Stat(filename)
if err != nil && os.IsNotExist(err) {
return false
}
return !stat.IsDir()
}
测试用例:
func TestExists(t *testing.T) {
dir := "/Users/cow/work/prog/golang/go_study/cmd"
if !Exists(dir) {
t.Errorf("%s is not a file!", dir)
}
file := "/Users/cow/work/prog/golang/go_study/cmd/main.go"
if !Exists(file) {
t.Errorf("%s is not a file!", file)
}
file = "/Users/cow/work/prog/golang/go_study/cmd/test.go"
if !Exists(file) {
t.Errorf("%s is not exists!", file)
}
}
二、os.Stat实现原理
1、函数原型
os.Stat方法定义如下:
// Stat returns a FileInfo describing the named file.
// If there is an error, it will be of type *PathError.
func Stat(name string) (FileInfo, error) {
testlog.Stat(name)
return statNolog(name)
}
2、FileInfo结构
os.Stat返回值包括FileInfo和error,FileInfo用来表示一个文件对象,其结构如下:
// A FileInfo describes a file and is returned by Stat and Lstat.
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() interface{} // underlying data source (can return nil)
}
3、FileStat结构
但FileInfo仅是一个Interface,FileStat实现了FileInfo接口,os.Stat实际返回指向FileStat的指针,FileStat其结构如下:
// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
type fileStat struct {
name string
size int64
mode FileMode
modTime time.Time
sys syscall.Stat_t
}
4、实现原理
os.Stat主要逻辑在statNolog方法,其实现如下:
// statNolog stats a file with no test logging.
func statNolog(name string) (FileInfo, error) {
var fs fileStat
err := syscall.Stat(name, &fs.sys)
if err != nil {
return nil, &PathError{"stat", name, err}
}
fillFileStatFromSys(&fs, name)
return &fs, nil
}
- syscall.Stat调用系统调用Stat方法获取文件属姓信息
func Stat(path string, stat *Stat_t) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := syscall(funcPC(libc_stat64_trampoline), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
- fillFileStatFromSys:根据文件属姓信息填充FileStat结构
func fillFileStatFromSys(fs *fileStat, name string) {
fs.name = basename(name)
fs.size = int64(fs.sys.Size)
fs.modTime = stTimespecToTime(fs.sys.Mtim)
fs.mode = FileMode(fs.sys.Mode & 0777)
switch fs.sys.Mode & syscall.S_IFMT {
case syscall.S_IFBLK:
fs.mode |= ModeDevice
case syscall.S_IFCHR:
fs.mode |= ModeDevice | ModeCharDevice
case syscall.S_IFDIR:
fs.mode |= ModeDir
case syscall.S_IFIFO:
fs.mode |= ModeNamedPipe
case syscall.S_IFLNK:
fs.mode |= ModeSymlink
case syscall.S_IFREG:
// nothing to do
case syscall.S_IFSOCK:
fs.mode |= ModeSocket
}
if fs.sys.Mode&syscall.S_ISGID != 0 {
fs.mode |= ModeSetgid
}
if fs.sys.Mode&syscall.S_ISUID != 0 {
fs.mode |= ModeSetuid
}
if fs.sys.Mode&syscall.S_ISVTX != 0 {
fs.mode |= ModeSticky
}
}
公众号:编程之蝉 专注后台开发、CDN、算法、大数据,欢迎关注,阅读最新更新