Files
gf/g/os/gfile/gfile.go

433 lines
10 KiB
Go
Raw Normal View History

2017-12-29 16:03:30 +08:00
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
2018-03-29 13:46:05 +08:00
// 文件管理.
2017-11-23 10:21:28 +08:00
package gfile
import (
"bytes"
"errors"
2018-10-22 13:19:06 +08:00
"fmt"
"gitee.com/johng/gf/g/container/gtype"
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g/util/gregex"
2018-10-22 13:19:06 +08:00
"io"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"sort"
"strings"
"time"
2017-11-23 10:21:28 +08:00
)
// 文件分隔符
2018-04-19 14:58:25 +08:00
const (
Separator = string(filepath.Separator)
// 默认的文件打开权限
gDEFAULT_PERM = 0666
2018-04-19 14:58:25 +08:00
)
2017-11-23 10:21:28 +08:00
2018-08-21 21:18:56 +08:00
var (
// 源码的main包所在目录仅仅会设置一次
mainPkgPath = gtype.NewString()
2018-08-21 21:18:56 +08:00
// 编译时的 GOROOT 数值
goRootOfBuild = gtype.NewString()
)
2017-11-23 10:21:28 +08:00
// 给定文件的绝对路径创建文件
func Mkdir(path string) error {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
return err
}
return nil
}
// 给定文件的绝对路径创建文件
func Create(path string) error {
2018-05-10 23:52:09 +08:00
dir := Dir(path)
if !Exists(dir) {
Mkdir(dir)
}
2017-11-23 10:21:28 +08:00
f, err := os.Create(path)
if err != nil {
return err
}
f.Close()
return nil
}
2018-10-22 18:58:11 +08:00
// 打开文件(os.O_RDWR|os.O_CREATE, 0666)
2017-11-23 10:21:28 +08:00
func Open(path string) (*os.File, error) {
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, gDEFAULT_PERM)
2017-11-23 10:21:28 +08:00
if err != nil {
return nil, err
}
return f, nil
}
2018-10-22 18:58:11 +08:00
// 打开文件(带flag)
2017-11-23 10:21:28 +08:00
func OpenWithFlag(path string, flag int) (*os.File, error) {
f, err := os.OpenFile(path, flag, gDEFAULT_PERM)
2017-11-23 10:21:28 +08:00
if err != nil {
return nil, err
}
return f, nil
}
2018-10-22 18:58:11 +08:00
// 打开文件(带flag&perm)
func OpenWithFlagPerm(path string, flag int, perm int) (*os.File, error) {
f, err := os.OpenFile(path, flag, os.FileMode(perm))
if err != nil {
return nil, err
}
return f, nil
}
2017-11-23 10:21:28 +08:00
// 判断所给路径文件/文件夹是否存在
func Exists(path string) bool {
2018-09-25 17:25:38 +08:00
if _, err := os.Stat(path); !os.IsNotExist(err) {
return true
}
return false
2017-11-23 10:21:28 +08:00
}
// 判断所给路径是否为文件夹
func IsDir(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
return s.IsDir()
}
2018-08-14 19:53:31 +08:00
// 获取当前工作目录
func Pwd() string {
pwd, _ := filepath.Abs(filepath.Dir(os.Args[0]))
return pwd
}
2017-11-23 10:21:28 +08:00
// 判断所给路径是否为文件
func IsFile(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
return !s.IsDir()
2017-11-23 10:21:28 +08:00
}
// 获取文件或目录信息
func Info(path string) *os.FileInfo {
info, err := os.Stat(path)
if err != nil {
return nil
}
return &info
}
// 文件移动/重命名
func Move(src string, dst string) error {
return os.Rename(src, dst)
}
// 文件移动/重命名
func Rename(src string, dst string) error {
return Move(src, dst)
}
// 文件复制
func Copy(src string, dst string) error {
srcFile, err := os.Open(src)
if err != nil {
return err
}
dstFile, err := os.Create(dst)
if err != nil {
return err
}
_, err = io.Copy(dstFile, srcFile)
if err != nil {
return err
}
err = dstFile.Sync()
if err != nil {
return err
}
srcFile.Close()
dstFile.Close()
return nil
}
// 返回目录下的文件名列表
func DirNames(path string) ([]string, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
list, err := f.Readdirnames(-1)
f.Close()
if err != nil {
return nil, err
}
return list, nil
}
// 文件名正则匹配查找,第二个可选参数指定返回的列表是否仅为文件名(非绝对路径),默认返回绝对路径
func Glob(pattern string, onlyNames...bool) ([]string, error) {
if list, err := filepath.Glob(pattern); err == nil {
if len(onlyNames) > 0 && onlyNames[0] && len(list) > 0 {
array := make([]string, len(list))
for k, v := range list {
array[k] = Basename(v)
}
return array, nil
}
return list, nil
} else {
return nil, err
}
}
2017-11-23 10:21:28 +08:00
// 文件/目录删除
func Remove(path string) error {
return os.RemoveAll(path)
}
2018-10-22 13:19:06 +08:00
// 文件是否可读
2017-11-23 10:21:28 +08:00
func IsReadable(path string) bool {
result := true
file, err := os.OpenFile(path, os.O_RDONLY, gDEFAULT_PERM)
2017-11-23 10:21:28 +08:00
if err != nil {
result = false
}
file.Close()
return result
}
// 文件是否可写
func IsWritable(path string) bool {
result := true
if IsDir(path) {
// 如果是目录,那么创建一个临时文件进行写入测试
tfile := strings.TrimRight(path, Separator) + Separator + gconv.String(time.Now().UnixNano())
2017-11-23 10:21:28 +08:00
err := Create(tfile)
if err != nil || !Exists(tfile){
result = false
} else {
Remove(tfile)
}
} else {
// 如果是文件,那么判断文件是否可打开
file, err := os.OpenFile(path, os.O_WRONLY, gDEFAULT_PERM)
2017-11-23 10:21:28 +08:00
if err != nil {
result = false
}
file.Close()
}
return result
}
// 修改文件/目录权限
func Chmod(path string, mode os.FileMode) error {
return os.Chmod(path, mode)
}
// 打开目录,并返回其下一级文件列表(绝对路径),按照文件名称大小写进行排序,支持目录递归遍历。
func ScanDir(path string, pattern string, recursive ... bool) ([]string, error) {
list, err := doScanDir(path, pattern, recursive...)
2017-11-23 10:21:28 +08:00
if err != nil {
return nil, err
2017-11-23 10:21:28 +08:00
}
if len(list) > 0 {
sort.Strings(list)
}
return list, nil
}
2017-11-23 10:21:28 +08:00
// 内部检索目录方法,支持递归,返回没有排序的文件绝对路径列表结果
func doScanDir(path string, pattern string, recursive ... bool) ([]string, error) {
var list []string
// 打开目录
dfile, err := os.Open(path)
2017-11-23 10:21:28 +08:00
if err != nil {
return nil, err
}
defer dfile.Close()
// 读取目录下的文件列表
names, err := dfile.Readdirnames(-1)
if err != nil {
return nil, err
2017-11-23 10:21:28 +08:00
}
// 是否递归遍历
2018-10-10 15:24:30 +08:00
for _, name := range names {
path := fmt.Sprintf("%s%s%s", path, Separator, name)
if IsDir(path) && len(recursive) > 0 && recursive[0] {
array, _ := doScanDir(path, pattern, true)
if len(array) > 0 {
list = append(list, array...)
}
}
2018-10-10 15:24:30 +08:00
// 满足pattern才加入结果列表
if match, err := filepath.Match(pattern, name); err == nil && match {
list = append(list, path)
}
}
return list, nil
2017-11-23 10:21:28 +08:00
}
// 将所给定的路径转换为绝对路径
// 并判断文件路径是否存在,如果文件不存在,那么返回空字符串
func RealPath(path string) string {
p, err := filepath.Abs(path)
if err != nil {
return ""
}
if !Exists(p) {
return ""
}
return p
}
// 获取当前执行文件的绝对路径
func SelfPath() string {
p, _ := filepath.Abs(os.Args[0])
return p
}
// 获取当前执行文件的目录绝对路径
func SelfDir() string {
return filepath.Dir(SelfPath())
}
// 获取指定文件路径的文件名称
func Basename(path string) string {
return filepath.Base(path)
}
// 获取指定文件路径的目录地址绝对路径
func Dir(path string) string {
return filepath.Dir(path)
}
2018-10-24 14:51:32 +08:00
// 获取指定文件路径的文件扩展名(包含"."号)
2017-11-23 10:21:28 +08:00
func Ext(path string) string {
return filepath.Ext(path)
}
// 获取用户主目录
func Home() (string, error) {
u, err := user.Current()
if nil == err {
return u.HomeDir, nil
}
if "windows" == runtime.GOOS {
return homeWindows()
}
return homeUnix()
}
func homeUnix() (string, error) {
if home := os.Getenv("HOME"); home != "" {
return home, nil
}
var stdout bytes.Buffer
cmd := exec.Command("sh", "-c", "eval echo ~$USER")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return "", err
}
result := strings.TrimSpace(stdout.String())
if result == "" {
return "", errors.New("blank output when reading home directory")
}
return result, nil
}
func homeWindows() (string, error) {
drive := os.Getenv("HOMEDRIVE")
path := os.Getenv("HOMEPATH")
home := drive + path
if drive == "" || path == "" {
home = os.Getenv("USERPROFILE")
}
if home == "" {
return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
}
return home, nil
}
// 获取入口函数文件所在目录(main包文件目录)
// **仅对源码开发环境有效(即仅对生成该可执行文件的系统下有效)**
func MainPkgPath() string {
path := mainPkgPath.Val()
if path != "" {
return path
}
f := ""
for i := 1; i < 10000; i++ {
if _, file, _, ok := runtime.Caller(i); ok {
if strings.EqualFold("<autogenerated>", file) {
// 如果是通过init包方法进入那么无法得到准确的文件路径
f = ""
} else {
goroot := GoRootOfBuild()
if goroot != "" && !gregex.IsMatchString("^" + GoRootOfBuild(), file) {
// 不包含go源码路径
f = file
}
}
} else {
break
}
}
if f != "" {
p := Dir(f)
mainPkgPath.Set(p)
return p
}
return ""
}
// 编译时环境的GOROOT数值(对init初始化方法调用时无效获取不了ROOT值)
// 注意:可能返回空
func GoRootOfBuild() string {
if v := goRootOfBuild.Val(); v != "" {
return v
}
firstEntry := ""
for i := 0; i < 10000; i++ {
if _, file, _, ok := runtime.Caller(i); ok {
firstEntry = file
} else {
break
}
}
if len(firstEntry) > 0 {
sep := "/"
array := strings.Split(firstEntry, sep)
if len(array) == 1 {
sep = "\\"
array = strings.Split(firstEntry, sep)
}
root := strings.Join(array[0 : len(array) - 3], sep)
goRootOfBuild.Set(root)
return root
}
return ""
}
// 系统临时目录
func TempDir() string {
return os.TempDir()
2017-11-23 10:21:28 +08:00
}