Golang判断文件是否存在跨平台方案及实现原理

一、判断文件是否存在
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、算法、大数据,欢迎关注,阅读最新更新
公众号:编程之蝉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值