1 Star 0 Fork 0

h79/goutils

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
file.go 7.89 KB
一键复制 编辑 原始数据 按行查看 历史
huqiuyun 提交于 2024-09-07 13:18 . time range
package file
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
func IsFile(f string) bool {
return IsDir(f) == 0
}
// DirEmpty 目录是否为空
func DirEmpty(path string) bool {
fs, e := filepath.Glob(filepath.Join(path, "*"))
if e != nil {
return false
}
if len(fs) > 0 {
return false
}
return true
}
func IsDir(f string) int {
fi, e := os.Stat(f)
if e != nil {
return -1
}
if fi.IsDir() {
return 1
}
return 0
}
// IsExist 文件或目录
func IsExist(f string) bool {
_, err := os.Stat(f)
return err == nil || os.IsExist(err)
}
// CopyFile is used to copy a file
func CopyFile(old, new string) error {
// Open the file and create a new one
r, err := os.Open(old)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(new)
if err != nil {
return err
}
defer w.Close()
// Copy the content
_, err = io.Copy(w, r)
if err != nil {
return err
}
return nil
}
func ReadFile(f *os.File) ([]byte, error) {
var size int
if info, err := f.Stat(); err == nil {
size64 := info.Size()
if int64(int(size64)) == size64 {
size = int(size64)
}
}
size++ // one byte for final read at EOF
// If a file claims a small size, read at least 512 bytes.
// In particular, files in Linux's /proc claim size 0 but
// then do not work right if read in small pieces,
// so an initial read of 1 byte would not work correctly.
if size < 512 {
size = 512
}
return Read(f, size)
}
func Read(f io.Reader, size int) ([]byte, error) {
if size < 0 {
return nil, io.ErrShortBuffer
}
data := make([]byte, 0, size)
for {
if len(data) >= cap(data) {
d := append(data[:cap(data)], 0)
data = d[:len(data)]
}
n, err := f.Read(data[len(data):cap(data)])
data = data[:len(data)+n]
if err != nil {
if err == io.EOF {
err = nil
}
return data, err
}
}
}
func CopyN(writer io.Writer, src io.Reader, size int64) (int64, error) {
const SIZE int64 = 4096
var total int64 = 0
for total < size {
if size > SIZE {
size = SIZE
}
n, err := io.CopyN(writer, src, size)
if err != nil {
return 0, err
}
total += n
}
return total, nil
}
func Write(filename string, src io.Reader, perm os.FileMode) error {
return WriteFileName(filename, perm, func(w *os.File) error {
_, err := io.Copy(w, src)
return err
})
}
func WriteOut(filename string, src io.Reader, perm os.FileMode, outer func(w *os.File) error) error {
return WriteFileName(filename, perm, func(w *os.File) error {
_, err := io.Copy(w, src)
if err != nil {
return err
}
return outer(w)
})
}
func WriteFileName(filename string, perm os.FileMode, writer func(w *os.File) error) error {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
}
defer f.Close()
return writer(f)
}
func CreateFile(filename string, perm os.FileMode) (*os.File, error) {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return nil, err
}
return f, err
}
func CreatePath(path string) error {
if len(path) == 0 {
return fmt.Errorf("path is empty")
}
return os.MkdirAll(path, os.ModePerm)
}
func Open(filename string) (*os.File, int64, error) {
src, err := os.Open(filename)
if err != nil {
return nil, 0, err
}
stat, err := src.Stat()
if err != nil {
src.Close()
return nil, 0, err
}
return src, stat.Size(), nil
}
type Depth struct {
Depth int
total int
}
func WithMaxDepth() Depth {
return Depth{Depth: 255}
}
func WithDepth(depth int) Depth {
return Depth{Depth: depth}
}
func CopyDir(dst, src string) error {
src, err := filepath.EvalSymlinks(src)
if err != nil {
return err
}
walkFn := func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path == src {
return nil
}
if strings.HasPrefix(filepath.Base(path), ".") {
// Skip any dot files
if info.IsDir() {
return filepath.SkipDir
} else {
return nil
}
}
// The "path" has the src prefixed to it. We need to join our
// destination with the path without the src on it.
dstPath := filepath.Join(dst, path[len(src):])
// we don't want to try and copy the same file over itself.
if eq, err := SameFile(path, dstPath); eq {
return nil
} else if err != nil {
return err
}
// If we have a directory, make that subdirectory, then continue
// the walk.
if info.IsDir() {
if path == filepath.Join(src, dst) {
// dst is in src; don't walk it.
return nil
}
if err := os.MkdirAll(dstPath, 0755); err != nil {
return err
}
return nil
}
// If the current path is a symlink, recreate the symlink relative to
// the dst directory
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
target, err := os.Readlink(path)
if err != nil {
return err
}
return os.Symlink(target, dstPath)
}
// If we have a file, copy the contents.
srcF, err := os.Open(path)
if err != nil {
return err
}
defer srcF.Close()
dstF, err := os.Create(dstPath)
if err != nil {
return err
}
defer dstF.Close()
if _, err := io.Copy(dstF, srcF); err != nil {
return err
}
// Chmod it
return os.Chmod(dstPath, info.Mode())
}
return filepath.Walk(src, walkFn)
}
// SameFile returns true if the two given paths refer to the same physical
// file on disk, using the unique file identifiers from the underlying
// operating system. For example, on Unix systems this checks whether the
// two files are on the same device and have the same inode.
func SameFile(a, b string) (bool, error) {
if a == b {
return true, nil
}
aInfo, err := os.Lstat(a)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
bInfo, err := os.Lstat(b)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
return os.SameFile(aInfo, bInfo), nil
}
// ReadDir handler return 1: ignore, 0: ok, other: err
func ReadDir(path string, depth *Depth, handler func(name string, isDir bool, entry os.DirEntry) int) error {
dir, err := os.ReadDir(path)
if err != nil {
return err
}
depth.total++
if depth.Depth < depth.total {
return nil
}
ret := 0
for i := range dir {
d := dir[i]
filename := filepath.Join(path, d.Name())
if d.IsDir() {
if ret = handler(filename, true, d); ret != 0 {
if ret == 1 { //ignore
continue
}
return fmt.Errorf("handler failure, code= %d", ret)
}
if depth.Depth < depth.total {
continue
}
de := Depth{Depth: depth.Depth, total: depth.total}
if err = ReadDir(filename, &de, handler); err != nil {
return err
}
} else if ret = handler(filename, false, d); ret != 0 {
if ret == 1 { //ignore
continue
}
return fmt.Errorf("handler failure, code= %d", ret)
}
}
return nil
}
func ReadFileName(filename string, reader func(r *os.File) error) (int64, error) {
src, err := os.Open(filename)
if err != nil {
return 0, err
}
defer src.Close()
stat, err := src.Stat()
if err != nil {
return 0, err
}
err = reader(src)
return stat.Size(), err
}
func ReadFileModifyTime(filename string, lastModifyTime int64) (int64, []byte, error) {
f, er := os.Open(filename)
if er != nil {
return lastModifyTime, nil, er
}
defer f.Close()
fileInfo, err := f.Stat()
if err != nil {
return lastModifyTime, nil, err
}
curModifyTime := fileInfo.ModTime().Unix()
if curModifyTime > lastModifyTime {
body, err := ReadFile(f)
if err != nil {
return lastModifyTime, nil, err
}
lastModifyTime = curModifyTime
return lastModifyTime, body, nil
}
return lastModifyTime, nil, ErrNotModified
}
type DecodeFunc func(v []byte) (interface{}, error)
func DecodeFileModifyTime(filename string, lastModifyTime int64, decoder DecodeFunc) (int64, interface{}, error) {
t, body, err := ReadFileModifyTime(filename, lastModifyTime)
if err != nil {
return t, nil, err
}
data, err := decoder(body)
if err != nil {
return lastModifyTime, nil, err
}
return t, data, nil
}
var ErrNotModified = errors.New("file not modified")
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/h79/goutils.git
git@gitee.com:h79/goutils.git
h79
goutils
goutils
v1.21.15

搜索帮助