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")