github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zfile/file.go (about)

     1  // Package zfile file and path operations in daily development
     2  package zfile
     3  
     4  import (
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"math"
     9  	"mime"
    10  	"net/http"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  )
    15  
    16  var (
    17  	ProjectPath = "./"
    18  )
    19  
    20  func init() {
    21  	// abs, _ := filepath.Abs(".")
    22  	// ProjectPath = RealPath(abs)
    23  	ProjectPath = ProgramPath()
    24  	if strings.Contains(ProjectPath, TmpPath("")) {
    25  		ProjectPath = RootPath()
    26  	}
    27  }
    28  
    29  // PathExist PathExist
    30  // 1 exists and is a directory path, 2 exists and is a file path, 0 does not exist
    31  func PathExist(path string) (int, error) {
    32  	path = RealPath(path)
    33  	f, err := os.Stat(path)
    34  	if err == nil {
    35  		isFile := 2
    36  		if f.IsDir() {
    37  			isFile = 1
    38  		}
    39  		return isFile, nil
    40  	}
    41  
    42  	return 0, err
    43  }
    44  
    45  // DirExist Is it an existing directory
    46  func DirExist(path string) bool {
    47  	state, _ := PathExist(path)
    48  	return state == 1
    49  }
    50  
    51  // FileExist Is it an existing file?
    52  func FileExist(path string) bool {
    53  	state, _ := PathExist(path)
    54  	return state == 2
    55  }
    56  
    57  // FileSize file size
    58  func FileSize(file string) (size string) {
    59  	return SizeFormat(FileSizeUint(file))
    60  }
    61  
    62  // FileSizeUint file size to uint64
    63  func FileSizeUint(file string) (size uint64) {
    64  	file = RealPath(file)
    65  	fileInfo, err := os.Stat(file)
    66  	if err != nil {
    67  		return 0
    68  	}
    69  	return uint64(fileInfo.Size())
    70  }
    71  
    72  // SizeFormat Format file size
    73  func SizeFormat(s uint64) string {
    74  	sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
    75  	humanateBytes := func(s uint64, base float64, sizes []string) string {
    76  		if s < 10 {
    77  			return fmt.Sprintf("%d B", s)
    78  		}
    79  		e := math.Floor(logSize(float64(s), base))
    80  		suffix := sizes[int(e)]
    81  		val := float64(s) / math.Pow(base, math.Floor(e))
    82  		f := "%.0f"
    83  		if val < 10 {
    84  			f = "%.1f"
    85  		}
    86  		return fmt.Sprintf(f+" %s", val, suffix)
    87  	}
    88  	return humanateBytes(s, 1024, sizes)
    89  }
    90  
    91  func logSize(n, b float64) float64 {
    92  	return math.Log(n) / math.Log(b)
    93  }
    94  
    95  // RootPath Project Launch Path
    96  func RootPath() string {
    97  	path, _ := filepath.Abs(".")
    98  	return RealPath(path)
    99  }
   100  
   101  func TmpPath(pattern ...string) string {
   102  	p := ""
   103  	if len(pattern) > 0 {
   104  		p = pattern[0]
   105  	}
   106  	path, _ := ioutil.TempDir("", p)
   107  	if p == "" {
   108  		path, _ = filepath.Split(path)
   109  	}
   110  	path, _ = filepath.EvalSymlinks(path)
   111  	return RealPath(path)
   112  }
   113  
   114  // SafePath get an safe absolute path
   115  func SafePath(path string, pathRange ...string) string {
   116  	base := ""
   117  	if len(pathRange) == 0 {
   118  		base = ProjectPath
   119  	} else {
   120  		base = RealPath(pathRange[0], false)
   121  	}
   122  	return strings.TrimPrefix(RealPath(path, false), base)
   123  }
   124  
   125  // RealPath get an absolute path
   126  func RealPath(path string, addSlash ...bool) (realPath string) {
   127  	if len(path) > 2 && path[1] == ':' {
   128  		realPath = path
   129  	} else {
   130  		if len(path) == 0 || (path[0] != '/' && !filepath.IsAbs(path)) {
   131  			path = ProjectPath + "/" + path
   132  		}
   133  		realPath, _ = filepath.Abs(path)
   134  	}
   135  
   136  	realPath = strings.Replace(realPath, "\\", "/", -1)
   137  	realPath = pathAddSlash(realPath, addSlash...)
   138  
   139  	return
   140  }
   141  
   142  // RealPathMkdir get an absolute path, create it if it doesn't exist
   143  func RealPathMkdir(path string, addSlash ...bool) string {
   144  	realPath := RealPath(path, addSlash...)
   145  	if DirExist(realPath) {
   146  		return realPath
   147  	}
   148  	_ = os.MkdirAll(realPath, os.ModePerm)
   149  	return realPath
   150  }
   151  
   152  // IsSubPath Is the subPath under the path
   153  func IsSubPath(subPath, path string) bool {
   154  	subPath = RealPath(subPath)
   155  	path = RealPath(path)
   156  	return strings.HasPrefix(subPath, path)
   157  }
   158  
   159  // Rmdir support to keep the current directory
   160  func Rmdir(path string, notIncludeSelf ...bool) (ok bool) {
   161  	realPath := RealPath(path)
   162  	err := os.RemoveAll(realPath)
   163  	ok = err == nil
   164  	if ok && len(notIncludeSelf) > 0 && notIncludeSelf[0] {
   165  		_ = os.Mkdir(path, os.ModePerm)
   166  	}
   167  	return
   168  }
   169  
   170  // Remove removes the named file or (empty) directory
   171  func Remove(path string) error {
   172  	realPath := RealPath(path)
   173  	return os.Remove(realPath)
   174  }
   175  
   176  // CopyFile copies the source file to the dest file.
   177  func CopyFile(source string, dest string) (err error) {
   178  	sourcefile, err := os.Open(source)
   179  	if err != nil {
   180  		return err
   181  	}
   182  	defer sourcefile.Close()
   183  	destfile, err := os.Create(dest)
   184  	if err != nil {
   185  		return err
   186  	}
   187  	defer destfile.Close()
   188  	_, err = io.Copy(destfile, sourcefile)
   189  	if err == nil {
   190  		var sourceinfo os.FileInfo
   191  		sourceinfo, err = os.Stat(source)
   192  		if err == nil {
   193  			err = os.Chmod(dest, sourceinfo.Mode())
   194  		}
   195  	}
   196  	return
   197  }
   198  
   199  // ProgramPath program directory path
   200  func ProgramPath(addSlash ...bool) (path string) {
   201  	ePath, err := os.Executable()
   202  	if err != nil {
   203  		ePath = ProjectPath
   204  	} else {
   205  		ePath = filepath.Dir(ePath)
   206  	}
   207  	realPath, err := filepath.EvalSymlinks(ePath)
   208  	if err == nil {
   209  		ePath = realPath
   210  	}
   211  	path = RealPath(ePath, addSlash...)
   212  
   213  	return
   214  }
   215  
   216  func pathAddSlash(path string, addSlash ...bool) string {
   217  	if len(addSlash) > 0 && addSlash[0] && !strings.HasSuffix(path, "/") {
   218  		path += "/"
   219  	}
   220  	return path
   221  }
   222  
   223  // GetMimeType get file mime type
   224  func GetMimeType(filename string, content []byte) (ctype string) {
   225  	if len(content) > 0 {
   226  		ctype = http.DetectContentType(content)
   227  	}
   228  
   229  	if filename != "" && (ctype == "" || strings.HasPrefix(ctype, "text/plain")) {
   230  		ntype := mime.TypeByExtension(filepath.Ext(filename))
   231  		if ntype != "" {
   232  			ctype = ntype
   233  		}
   234  	}
   235  	return ctype
   236  }