gitee.com/h79/goutils@v1.22.10/common/file/file.go (about) 1 package file 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "os" 8 "path/filepath" 9 "strings" 10 ) 11 12 func IsFile(f string) bool { 13 return IsDir(f) == 0 14 } 15 16 // DirEmpty 目录是否为空 17 func DirEmpty(path string) bool { 18 fs, e := filepath.Glob(filepath.Join(path, "*")) 19 if e != nil { 20 return false 21 } 22 if len(fs) > 0 { 23 return false 24 } 25 return true 26 } 27 28 func IsDir(f string) int { 29 fi, e := os.Stat(f) 30 if e != nil { 31 return -1 32 } 33 if fi.IsDir() { 34 return 1 35 } 36 return 0 37 } 38 39 // IsExist 文件或目录 40 func IsExist(f string) bool { 41 _, err := os.Stat(f) 42 return err == nil || os.IsExist(err) 43 } 44 45 // CopyFile is used to copy a file 46 func CopyFile(old, new string) error { 47 // Open the file and create a new one 48 r, err := os.Open(old) 49 if err != nil { 50 return err 51 } 52 defer r.Close() 53 54 w, err := os.Create(new) 55 if err != nil { 56 return err 57 } 58 defer w.Close() 59 60 // Copy the content 61 _, err = io.Copy(w, r) 62 if err != nil { 63 return err 64 } 65 66 return nil 67 } 68 69 func ReadFile(f *os.File) ([]byte, error) { 70 71 var size int 72 if info, err := f.Stat(); err == nil { 73 size64 := info.Size() 74 if int64(int(size64)) == size64 { 75 size = int(size64) 76 } 77 } 78 size++ // one byte for final read at EOF 79 80 // If a file claims a small size, read at least 512 bytes. 81 // In particular, files in Linux's /proc claim size 0 but 82 // then do not work right if read in small pieces, 83 // so an initial read of 1 byte would not work correctly. 84 if size < 512 { 85 size = 512 86 } 87 return Read(f, size) 88 } 89 90 func Read(f io.Reader, size int) ([]byte, error) { 91 if size < 0 { 92 return nil, io.ErrShortBuffer 93 } 94 data := make([]byte, 0, size) 95 for { 96 if len(data) >= cap(data) { 97 d := append(data[:cap(data)], 0) 98 data = d[:len(data)] 99 } 100 n, err := f.Read(data[len(data):cap(data)]) 101 data = data[:len(data)+n] 102 if err != nil { 103 if err == io.EOF { 104 err = nil 105 } 106 return data, err 107 } 108 } 109 } 110 111 func CopyN(writer io.Writer, src io.Reader, size int64) (int64, error) { 112 const SIZE int64 = 4096 113 var total int64 = 0 114 for total < size { 115 if size > SIZE { 116 size = SIZE 117 } 118 n, err := io.CopyN(writer, src, size) 119 if err != nil { 120 return 0, err 121 } 122 total += n 123 } 124 return total, nil 125 } 126 127 func Write(filename string, src io.Reader, perm os.FileMode) error { 128 return WriteFileName(filename, perm, func(w *os.File) error { 129 _, err := io.Copy(w, src) 130 return err 131 }) 132 } 133 134 func WriteOut(filename string, src io.Reader, perm os.FileMode, outer func(w *os.File) error) error { 135 return WriteFileName(filename, perm, func(w *os.File) error { 136 _, err := io.Copy(w, src) 137 if err != nil { 138 return err 139 } 140 return outer(w) 141 }) 142 } 143 144 func WriteFileName(filename string, perm os.FileMode, writer func(w *os.File) error) error { 145 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) 146 if err != nil { 147 return err 148 } 149 defer f.Close() 150 151 return writer(f) 152 } 153 154 func CreateFile(filename string, perm os.FileMode) (*os.File, error) { 155 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) 156 if err != nil { 157 return nil, err 158 } 159 return f, err 160 } 161 162 func CreatePath(path string) error { 163 if len(path) == 0 { 164 return fmt.Errorf("path is empty") 165 } 166 return os.MkdirAll(path, os.ModePerm) 167 } 168 169 func Open(filename string) (*os.File, int64, error) { 170 src, err := os.Open(filename) 171 if err != nil { 172 return nil, 0, err 173 } 174 stat, err := src.Stat() 175 if err != nil { 176 src.Close() 177 return nil, 0, err 178 } 179 return src, stat.Size(), nil 180 } 181 182 type Depth struct { 183 Depth int 184 total int 185 } 186 187 func WithMaxDepth() Depth { 188 return Depth{Depth: 255} 189 } 190 191 func WithDepth(depth int) Depth { 192 return Depth{Depth: depth} 193 } 194 195 func CopyDir(dst, src string) error { 196 src, err := filepath.EvalSymlinks(src) 197 if err != nil { 198 return err 199 } 200 201 walkFn := func(path string, info os.FileInfo, err error) error { 202 if err != nil { 203 return err 204 } 205 if path == src { 206 return nil 207 } 208 if strings.HasPrefix(filepath.Base(path), ".") { 209 // Skip any dot files 210 if info.IsDir() { 211 return filepath.SkipDir 212 } else { 213 return nil 214 } 215 } 216 217 // The "path" has the src prefixed to it. We need to join our 218 // destination with the path without the src on it. 219 dstPath := filepath.Join(dst, path[len(src):]) 220 221 // we don't want to try and copy the same file over itself. 222 if eq, err := SameFile(path, dstPath); eq { 223 return nil 224 } else if err != nil { 225 return err 226 } 227 228 // If we have a directory, make that subdirectory, then continue 229 // the walk. 230 if info.IsDir() { 231 if path == filepath.Join(src, dst) { 232 // dst is in src; don't walk it. 233 return nil 234 } 235 if err := os.MkdirAll(dstPath, 0755); err != nil { 236 return err 237 } 238 return nil 239 } 240 241 // If the current path is a symlink, recreate the symlink relative to 242 // the dst directory 243 if info.Mode()&os.ModeSymlink == os.ModeSymlink { 244 target, err := os.Readlink(path) 245 if err != nil { 246 return err 247 } 248 return os.Symlink(target, dstPath) 249 } 250 251 // If we have a file, copy the contents. 252 srcF, err := os.Open(path) 253 if err != nil { 254 return err 255 } 256 defer srcF.Close() 257 258 dstF, err := os.Create(dstPath) 259 if err != nil { 260 return err 261 } 262 defer dstF.Close() 263 264 if _, err := io.Copy(dstF, srcF); err != nil { 265 return err 266 } 267 268 // Chmod it 269 return os.Chmod(dstPath, info.Mode()) 270 } 271 272 return filepath.Walk(src, walkFn) 273 } 274 275 // SameFile returns true if the two given paths refer to the same physical 276 // file on disk, using the unique file identifiers from the underlying 277 // operating system. For example, on Unix systems this checks whether the 278 // two files are on the same device and have the same inode. 279 func SameFile(a, b string) (bool, error) { 280 if a == b { 281 return true, nil 282 } 283 284 aInfo, err := os.Lstat(a) 285 if err != nil { 286 if os.IsNotExist(err) { 287 return false, nil 288 } 289 return false, err 290 } 291 292 bInfo, err := os.Lstat(b) 293 if err != nil { 294 if os.IsNotExist(err) { 295 return false, nil 296 } 297 return false, err 298 } 299 300 return os.SameFile(aInfo, bInfo), nil 301 } 302 303 // ReadDir handler return 1: ignore, 0: ok, other: err 304 func ReadDir(path string, depth *Depth, handler func(name string, isDir bool, entry os.DirEntry) int) error { 305 dir, err := os.ReadDir(path) 306 if err != nil { 307 return err 308 } 309 depth.total++ 310 if depth.Depth < depth.total { 311 return nil 312 } 313 ret := 0 314 for i := range dir { 315 d := dir[i] 316 filename := filepath.Join(path, d.Name()) 317 if d.IsDir() { 318 if ret = handler(filename, true, d); ret != 0 { 319 if ret == 1 { //ignore 320 continue 321 } 322 return fmt.Errorf("handler failure, code= %d", ret) 323 } 324 if depth.Depth < depth.total { 325 continue 326 } 327 de := Depth{Depth: depth.Depth, total: depth.total} 328 if err = ReadDir(filename, &de, handler); err != nil { 329 return err 330 } 331 } else if ret = handler(filename, false, d); ret != 0 { 332 if ret == 1 { //ignore 333 continue 334 } 335 return fmt.Errorf("handler failure, code= %d", ret) 336 } 337 } 338 return nil 339 } 340 341 func ReadFileName(filename string, reader func(r *os.File) error) (int64, error) { 342 src, err := os.Open(filename) 343 if err != nil { 344 return 0, err 345 } 346 defer src.Close() 347 stat, err := src.Stat() 348 if err != nil { 349 return 0, err 350 } 351 err = reader(src) 352 return stat.Size(), err 353 } 354 355 func ReadFileModifyTime(filename string, lastModifyTime int64) (int64, []byte, error) { 356 f, er := os.Open(filename) 357 if er != nil { 358 return lastModifyTime, nil, er 359 } 360 defer f.Close() 361 fileInfo, err := f.Stat() 362 if err != nil { 363 return lastModifyTime, nil, err 364 } 365 curModifyTime := fileInfo.ModTime().Unix() 366 if curModifyTime > lastModifyTime { 367 body, err := ReadFile(f) 368 if err != nil { 369 return lastModifyTime, nil, err 370 } 371 lastModifyTime = curModifyTime 372 return lastModifyTime, body, nil 373 } 374 return lastModifyTime, nil, ErrNotModified 375 } 376 377 type DecodeFunc func(v []byte) (interface{}, error) 378 379 func DecodeFileModifyTime(filename string, lastModifyTime int64, decoder DecodeFunc) (int64, interface{}, error) { 380 t, body, err := ReadFileModifyTime(filename, lastModifyTime) 381 if err != nil { 382 return t, nil, err 383 } 384 data, err := decoder(body) 385 if err != nil { 386 return lastModifyTime, nil, err 387 } 388 return t, data, nil 389 } 390 391 var ErrNotModified = errors.New("file not modified")