Initial QSfera import
This commit is contained in:
+337
@@ -0,0 +1,337 @@
|
||||
package fsutil
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/x/basefn"
|
||||
)
|
||||
|
||||
// Mkdir alias of os.MkdirAll()
|
||||
func Mkdir(dirPath string, perm fs.FileMode) error { return os.MkdirAll(dirPath, perm) }
|
||||
|
||||
// MkdirQuick with default permission 0755.
|
||||
func MkdirQuick(dirPath string) error { return EnsureDir(dirPath) }
|
||||
|
||||
// EnsureDir creates a directory if it doesn't exist
|
||||
func EnsureDir(path string) error {
|
||||
if !DirExist(path) {
|
||||
return os.MkdirAll(path, 0755)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MkDirs batch makes multi dirs at once
|
||||
func MkDirs(perm fs.FileMode, dirPaths ...string) error {
|
||||
for _, dirPath := range dirPaths {
|
||||
if err := os.MkdirAll(dirPath, perm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MkSubDirs batch makes multi sub-dirs at once
|
||||
func MkSubDirs(perm fs.FileMode, parentDir string, subDirs ...string) error {
|
||||
for _, dirName := range subDirs {
|
||||
dirPath := parentDir + "/" + dirName
|
||||
if err := os.MkdirAll(dirPath, perm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MkParentDir quickly create parent dir for a given path.
|
||||
func MkParentDir(fpath string) error {
|
||||
dirPath := filepath.Dir(fpath)
|
||||
if !IsDir(dirPath) {
|
||||
return os.MkdirAll(dirPath, 0775)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// options for open file
|
||||
// ************************************************************
|
||||
|
||||
// OpenOption for open file
|
||||
type OpenOption struct {
|
||||
// file open flag. see FsCWTFlags
|
||||
Flag int
|
||||
// file perm. see DefaultFilePerm
|
||||
Perm os.FileMode
|
||||
}
|
||||
|
||||
// OpenOptionFunc for open/write file
|
||||
type OpenOptionFunc func(*OpenOption)
|
||||
|
||||
// NewOpenOption create a new OpenOption instance
|
||||
//
|
||||
// Defaults:
|
||||
// - open flags: FsCWTFlags (override write)
|
||||
// - file Perm: DefaultFilePerm
|
||||
func NewOpenOption(optFns ...OpenOptionFunc) *OpenOption {
|
||||
opt := &OpenOption{
|
||||
Flag: FsCWTFlags,
|
||||
Perm: DefaultFilePerm,
|
||||
}
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(opt)
|
||||
}
|
||||
return opt
|
||||
}
|
||||
|
||||
// OpenOptOrNew create a new OpenOption instance if opt is nil
|
||||
func OpenOptOrNew(opt *OpenOption) *OpenOption {
|
||||
if opt == nil {
|
||||
return NewOpenOption()
|
||||
}
|
||||
return opt
|
||||
}
|
||||
|
||||
// WithFlag set file open flag
|
||||
func WithFlag(flag int) OpenOptionFunc {
|
||||
return func(opt *OpenOption) {
|
||||
opt.Flag = flag
|
||||
}
|
||||
}
|
||||
|
||||
// WithPerm set file perm
|
||||
func WithPerm(perm os.FileMode) OpenOptionFunc {
|
||||
return func(opt *OpenOption) {
|
||||
opt.Perm = perm
|
||||
}
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// open/create files
|
||||
// ************************************************************
|
||||
|
||||
// some commonly flag consts for open file.
|
||||
const (
|
||||
FsCWAFlags = os.O_CREATE | os.O_WRONLY | os.O_APPEND // create, append write-only
|
||||
FsCWTFlags = os.O_CREATE | os.O_WRONLY | os.O_TRUNC // create, override write-only
|
||||
FsCWFlags = os.O_CREATE | os.O_WRONLY // create, write-only
|
||||
FsRWFlags = os.O_RDWR // read-write, dont create.
|
||||
FsRFlags = os.O_RDONLY // read-only
|
||||
)
|
||||
|
||||
// OpenFile like os.OpenFile, but will auto create dir.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// file, err := OpenFile("path/to/file.txt", FsCWFlags, 0666)
|
||||
func OpenFile(filePath string, flag int, perm os.FileMode) (*os.File, error) {
|
||||
fileDir := filepath.Dir(filePath)
|
||||
if err := os.MkdirAll(fileDir, DefaultDirPerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(filePath, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// MustOpenFile like os.OpenFile, but will auto create dir.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// file := MustOpenFile("path/to/file.txt", FsCWFlags, 0666)
|
||||
func MustOpenFile(filePath string, flag int, perm os.FileMode) *os.File {
|
||||
file, err := OpenFile(filePath, flag, perm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
// QuickOpenFile like os.OpenFile, open for append write. if not exists, will create it.
|
||||
//
|
||||
// Alias of OpenAppendFile()
|
||||
func QuickOpenFile(filepath string, fileFlag ...int) (*os.File, error) {
|
||||
flag := basefn.FirstOr(fileFlag, FsCWAFlags)
|
||||
return OpenFile(filepath, flag, DefaultFilePerm)
|
||||
}
|
||||
|
||||
// OpenAppendFile like os.OpenFile, open for append write. if not exists, will create it.
|
||||
func OpenAppendFile(filepath string, filePerm ...os.FileMode) (*os.File, error) {
|
||||
perm := basefn.FirstOr(filePerm, DefaultFilePerm)
|
||||
return OpenFile(filepath, FsCWAFlags, perm)
|
||||
}
|
||||
|
||||
// OpenTruncFile like os.OpenFile, open for override write. if not exists, will create it.
|
||||
func OpenTruncFile(filepath string, filePerm ...os.FileMode) (*os.File, error) {
|
||||
perm := basefn.FirstOr(filePerm, DefaultFilePerm)
|
||||
return OpenFile(filepath, FsCWTFlags, perm)
|
||||
}
|
||||
|
||||
// OpenReadFile like os.OpenFile, open file for read contents
|
||||
func OpenReadFile(filepath string) (*os.File, error) {
|
||||
return os.OpenFile(filepath, FsRFlags, OnlyReadFilePerm)
|
||||
}
|
||||
|
||||
// CreateFile create file if not exists
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// CreateFile("path/to/file.txt", 0664, 0666)
|
||||
func CreateFile(fpath string, filePerm, dirPerm os.FileMode, fileFlag ...int) (*os.File, error) {
|
||||
dirPath := filepath.Dir(fpath)
|
||||
if !IsDir(dirPath) {
|
||||
err := os.MkdirAll(dirPath, dirPerm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
flag := basefn.FirstOr(fileFlag, FsCWAFlags)
|
||||
return os.OpenFile(fpath, flag, filePerm)
|
||||
}
|
||||
|
||||
// MustCreateFile create file, will panic on error
|
||||
func MustCreateFile(filePath string, filePerm, dirPerm os.FileMode) *os.File {
|
||||
file, err := CreateFile(filePath, filePerm, dirPerm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// remove files
|
||||
// ************************************************************
|
||||
|
||||
// alias methods
|
||||
var (
|
||||
// MustRm removes the named file or (empty) directory.
|
||||
MustRm = MustRemove
|
||||
// QuietRm removes the named file or (empty) directory.
|
||||
QuietRm = QuietRemove
|
||||
)
|
||||
|
||||
// Remove removes the named file or (empty) directory.
|
||||
func Remove(fPath string) error {
|
||||
return os.Remove(fPath)
|
||||
}
|
||||
|
||||
// MustRemove removes the named file or (empty) directory.
|
||||
// NOTICE: will panic on error
|
||||
func MustRemove(fPath string) {
|
||||
if err := os.Remove(fPath); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// QuietRemove removes the named file or (empty) directory.
|
||||
//
|
||||
// NOTICE: will ignore error
|
||||
func QuietRemove(fPath string) { _ = os.Remove(fPath) }
|
||||
|
||||
// SafeRemoveAll removes path and any children it contains. will ignore error
|
||||
func SafeRemoveAll(path string) {
|
||||
_ = os.RemoveAll(path)
|
||||
}
|
||||
|
||||
// RmIfExist removes the named file or (empty) directory on existing.
|
||||
func RmIfExist(fPath string) error { return DeleteIfExist(fPath) }
|
||||
|
||||
// DeleteIfExist removes the named file or (empty) directory on existing.
|
||||
func DeleteIfExist(fPath string) error {
|
||||
if PathExists(fPath) {
|
||||
return os.Remove(fPath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RmFileIfExist removes the named file on existing.
|
||||
func RmFileIfExist(fPath string) error { return DeleteIfFileExist(fPath) }
|
||||
|
||||
// DeleteIfFileExist removes the named file on existing.
|
||||
func DeleteIfFileExist(fPath string) error {
|
||||
if IsFile(fPath) {
|
||||
return os.Remove(fPath)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveSub removes all sub files and dirs of dirPath, but not remove dirPath.
|
||||
func RemoveSub(dirPath string, fns ...FilterFunc) error {
|
||||
return FindInDir(dirPath, func(fPath string, ent fs.DirEntry) error {
|
||||
if ent.IsDir() {
|
||||
if err := RemoveSub(fPath, fns...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// skip rm not empty subdir
|
||||
if !IsEmptyDir(fPath) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return os.Remove(fPath)
|
||||
}, fns...)
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// other operates
|
||||
// ************************************************************
|
||||
|
||||
// Unzip a zip archive
|
||||
// from https://blog.csdn.net/wangshubo1989/article/details/71743374
|
||||
func Unzip(archive, targetDir string) (err error) {
|
||||
reader, err := zip.OpenReader(archive)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(targetDir, DefaultDirPerm); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, file := range reader.File {
|
||||
if strings.Contains(file.Name, "..") {
|
||||
return fmt.Errorf("illegal file path in zip: %v", file.Name)
|
||||
}
|
||||
|
||||
fullPath := filepath.Join(targetDir, file.Name)
|
||||
|
||||
if file.FileInfo().IsDir() {
|
||||
err = os.MkdirAll(fullPath, file.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
fileReader, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
targetFile, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
|
||||
if err != nil {
|
||||
_ = fileReader.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(targetFile, fileReader)
|
||||
|
||||
// close all
|
||||
_ = fileReader.Close()
|
||||
targetFile.Close()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user