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 }