123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- package file
- import (
- "bufio"
- "errors"
- "fmt"
- "io"
- "io/fs"
- "io/ioutil"
- "log"
- "mime/multipart"
- "os"
- "path"
- path2 "path"
- "path/filepath"
- "strconv"
- "strings"
- "github.com/mholt/archiver/v3"
- )
- // GetSize get the file size
- func GetSize(f multipart.File) (int, error) {
- content, err := ioutil.ReadAll(f)
- return len(content), err
- }
- // GetExt get the file ext
- func GetExt(fileName string) string {
- return path.Ext(fileName)
- }
- // CheckNotExist check if the file exists
- func CheckNotExist(src string) bool {
- _, err := os.Stat(src)
- return os.IsNotExist(err)
- }
- // CheckPermission check if the file has permission
- func CheckPermission(src string) bool {
- _, err := os.Stat(src)
- return os.IsPermission(err)
- }
- // IsNotExistMkDir create a directory if it does not exist
- func IsNotExistMkDir(src string) error {
- if notExist := CheckNotExist(src); notExist {
- if err := MkDir(src); err != nil {
- return err
- }
- }
- return nil
- }
- // MkDir create a directory
- func MkDir(src string) error {
- err := os.MkdirAll(src, os.ModePerm)
- if err != nil {
- return err
- }
- os.Chmod(src, 0o777)
- return nil
- }
- // RMDir remove a directory
- func RMDir(src string) error {
- err := os.RemoveAll(src)
- if err != nil {
- return err
- }
- os.Remove(src)
- return nil
- }
- // Open a file according to a specific mode
- func Open(name string, flag int, perm os.FileMode) (*os.File, error) {
- f, err := os.OpenFile(name, flag, perm)
- if err != nil {
- return nil, err
- }
- return f, nil
- }
- // MustOpen maximize trying to open the file
- func MustOpen(fileName, filePath string) (*os.File, error) {
- //dir, err := os.Getwd()
- //if err != nil {
- // return nil, fmt.Errorf("os.Getwd err: %v", err)
- //}
- src := filePath
- perm := CheckPermission(src)
- if perm == true {
- return nil, fmt.Errorf("file.CheckPermission Permission denied src: %s", src)
- }
- err := IsNotExistMkDir(src)
- if err != nil {
- return nil, fmt.Errorf("file.IsNotExistMkDir src: %s, err: %v", src, err)
- }
- f, err := Open(src+fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o644)
- if err != nil {
- return nil, fmt.Errorf("Fail to OpenFile :%v", err)
- }
- return f, nil
- }
- // 判断所给路径文件/文件夹是否存在
- func Exists(path string) bool {
- _, err := os.Stat(path) // os.Stat获取文件信息
- if err != nil {
- if os.IsExist(err) {
- return true
- }
- return false
- }
- return true
- }
- // 判断所给路径是否为文件夹
- func IsDir(path string) bool {
- s, err := os.Stat(path)
- if err != nil {
- return false
- }
- return s.IsDir()
- }
- // 判断所给路径是否为文件
- func IsFile(path string) bool {
- return !IsDir(path)
- }
- func CreateFile(path string) error {
- file, err := os.Create(path)
- if err != nil {
- return err
- }
- defer file.Close()
- return nil
- }
- func CreateFileAndWriteContent(path string, content string) error {
- file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o666)
- if err != nil {
- return err
- }
- defer file.Close()
- write := bufio.NewWriter(file)
- write.WriteString(content)
- write.Flush()
- return nil
- }
- // IsNotExistMkDir create a directory if it does not exist
- func IsNotExistCreateFile(src string) error {
- if notExist := CheckNotExist(src); notExist {
- if err := CreateFile(src); err != nil {
- return err
- }
- }
- return nil
- }
- func ReadFullFile(path string) []byte {
- file, err := os.Open(path)
- if err != nil {
- return []byte("")
- }
- defer file.Close()
- content, err := ioutil.ReadAll(file)
- if err != nil {
- return []byte("")
- }
- return content
- }
- // File copies a single file from src to dst
- func CopyFile(src, dst, style string) error {
- var err error
- var srcfd *os.File
- var dstfd *os.File
- var srcinfo os.FileInfo
- lastPath := src[strings.LastIndex(src, "/")+1:]
- if !strings.HasSuffix(dst, "/") {
- dst += "/"
- }
- dst += lastPath
- if Exists(dst) {
- if style == "skip" {
- return nil
- } else {
- os.Remove(dst)
- }
- }
- if srcfd, err = os.Open(src); err != nil {
- return err
- }
- defer srcfd.Close()
- if dstfd, err = os.Create(dst); err != nil {
- return err
- }
- defer dstfd.Close()
- if _, err = io.Copy(dstfd, srcfd); err != nil {
- return err
- }
- if srcinfo, err = os.Stat(src); err != nil {
- return err
- }
- return os.Chmod(dst, srcinfo.Mode())
- }
- /**
- * @description:
- * @param {*} src
- * @param {*} dst
- * @param {string} style
- * @return {*}
- * @method:
- * @router:
- */
- func CopySingleFile(src, dst, style string) error {
- var err error
- var srcfd *os.File
- var dstfd *os.File
- var srcinfo os.FileInfo
- if Exists(dst) {
- if style == "skip" {
- return nil
- } else {
- os.Remove(dst)
- }
- }
- if srcfd, err = os.Open(src); err != nil {
- return err
- }
- defer srcfd.Close()
- if dstfd, err = os.Create(dst); err != nil {
- return err
- }
- defer dstfd.Close()
- if _, err = io.Copy(dstfd, srcfd); err != nil {
- return err
- }
- if srcinfo, err = os.Stat(src); err != nil {
- return err
- }
- return os.Chmod(dst, srcinfo.Mode())
- }
- // Check for duplicate file names
- func GetNoDuplicateFileName(fullPath string) string {
- path, fileName := filepath.Split(fullPath)
- fileSuffix := path2.Ext(fileName)
- filenameOnly := strings.TrimSuffix(fileName, fileSuffix)
- for i := 0; Exists(fullPath); i++ {
- fullPath = path2.Join(path, filenameOnly+"("+strconv.Itoa(i+1)+")"+fileSuffix)
- }
- return fullPath
- }
- // Dir copies a whole directory recursively
- func CopyDir(src string, dst string, style string) error {
- var err error
- var fds []os.FileInfo
- var srcinfo os.FileInfo
- if srcinfo, err = os.Stat(src); err != nil {
- return err
- }
- if !srcinfo.IsDir() {
- if err = CopyFile(src, dst, style); err != nil {
- fmt.Println(err)
- }
- return nil
- }
- // dstPath := dst
- lastPath := src[strings.LastIndex(src, "/")+1:]
- dst += "/" + lastPath
- // for i := 0; Exists(dst); i++ {
- // dst = dstPath + "/" + lastPath + strconv.Itoa(i+1)
- // }
- if Exists(dst) {
- if style == "skip" {
- return nil
- } else {
- os.Remove(dst)
- }
- }
- if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
- return err
- }
- if fds, err = ioutil.ReadDir(src); err != nil {
- return err
- }
- for _, fd := range fds {
- srcfp := path.Join(src, fd.Name())
- dstfp := dst // path.Join(dst, fd.Name())
- if fd.IsDir() {
- if err = CopyDir(srcfp, dstfp, style); err != nil {
- fmt.Println(err)
- }
- } else {
- if err = CopyFile(srcfp, dstfp, style); err != nil {
- fmt.Println(err)
- }
- }
- }
- return nil
- }
- func WriteToPath(data []byte, path, name string) error {
- fullPath := path
- if strings.HasSuffix(path, "/") {
- fullPath += name
- } else {
- fullPath += "/" + name
- }
- return WriteToFullPath(data, fullPath, 0o666)
- }
- func WriteToFullPath(data []byte, fullPath string, perm fs.FileMode) error {
- if err := IsNotExistCreateFile(fullPath); err != nil {
- return err
- }
- file, err := os.OpenFile(fullPath,
- os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
- perm,
- )
- if err != nil {
- return err
- }
- defer file.Close()
- _, err = file.Write(data)
- return err
- }
- // 最终拼接
- func SpliceFiles(dir, path string, length int, startPoint int) error {
- fullPath := path
- if err := IsNotExistCreateFile(fullPath); err != nil {
- return err
- }
- file, _ := os.OpenFile(fullPath,
- os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
- 0o666,
- )
- defer file.Close()
- bufferedWriter := bufio.NewWriter(file)
- // todo: here should have a goroutine to remove each partial file after it is read, to save disk space
- for i := 0; i < length+startPoint; i++ {
- data, err := ioutil.ReadFile(dir + "/" + strconv.Itoa(i+startPoint))
- if err != nil {
- return err
- }
- if _, err := bufferedWriter.Write(data); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster write
- return err
- }
- }
- bufferedWriter.Flush()
- return nil
- }
- func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) {
- switch t {
- case "zip", "":
- return ".zip", archiver.NewZip(), nil
- case "tar":
- return ".tar", archiver.NewTar(), nil
- case "targz":
- return ".tar.gz", archiver.NewTarGz(), nil
- case "tarbz2":
- return ".tar.bz2", archiver.NewTarBz2(), nil
- case "tarxz":
- return ".tar.xz", archiver.NewTarXz(), nil
- case "tarlz4":
- return ".tar.lz4", archiver.NewTarLz4(), nil
- case "tarsz":
- return ".tar.sz", archiver.NewTarSz(), nil
- default:
- return "", nil, errors.New("format not implemented")
- }
- }
- func AddFile(ar archiver.Writer, path, commonPath string) error {
- info, err := os.Stat(path)
- if err != nil {
- return err
- }
- if !info.IsDir() && !info.Mode().IsRegular() {
- return nil
- }
- file, err := os.Open(path)
- if err != nil {
- return err
- }
- defer file.Close()
- if path != commonPath {
- filename := info.Name()
- err = ar.Write(archiver.File{
- FileInfo: archiver.FileInfo{
- FileInfo: info,
- CustomName: filename,
- },
- ReadCloser: file,
- })
- if err != nil {
- return err
- }
- }
- if info.IsDir() {
- names, err := file.Readdirnames(0)
- if err != nil {
- return err
- }
- for _, name := range names {
- err = AddFile(ar, filepath.Join(path, name), commonPath)
- if err != nil {
- log.Printf("Failed to archive %v", err)
- }
- }
- }
- return nil
- }
- func CommonPrefix(sep byte, paths ...string) string {
- // Handle special cases.
- switch len(paths) {
- case 0:
- return ""
- case 1:
- return path.Clean(paths[0])
- }
- // Note, we treat string as []byte, not []rune as is often
- // done in Go. (And sep as byte, not rune). This is because
- // most/all supported OS' treat paths as string of non-zero
- // bytes. A filename may be displayed as a sequence of Unicode
- // runes (typically encoded as UTF-8) but paths are
- // not required to be valid UTF-8 or in any normalized form
- // (e.g. "é" (U+00C9) and "é" (U+0065,U+0301) are different
- // file names.
- c := []byte(path.Clean(paths[0]))
- // We add a trailing sep to handle the case where the
- // common prefix directory is included in the path list
- // (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
- // path.Clean will have cleaned off trailing / separators with
- // the exception of the root directory, "/" (in which case we
- // make it "//", but this will get fixed up to "/" bellow).
- c = append(c, sep)
- // Ignore the first path since it's already in c
- for _, v := range paths[1:] {
- // Clean up each path before testing it
- v = path.Clean(v) + string(sep)
- // Find the first non-common byte and truncate c
- if len(v) < len(c) {
- c = c[:len(v)]
- }
- for i := 0; i < len(c); i++ {
- if v[i] != c[i] {
- c = c[:i]
- break
- }
- }
- }
- // Remove trailing non-separator characters and the final separator
- for i := len(c) - 1; i >= 0; i-- {
- if c[i] == sep {
- c = c[:i]
- break
- }
- }
- return string(c)
- }
- func GetFileOrDirSize(path string) (int64, error) {
- fileInfo, err := os.Stat(path)
- if err != nil {
- return 0, err
- }
- if fileInfo.IsDir() {
- return DirSizeB(path + "/")
- }
- return fileInfo.Size(), nil
- }
- // getFileSize get file size by path(B)
- func DirSizeB(path string) (int64, error) {
- var size int64
- err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
- if !info.IsDir() {
- size += info.Size()
- }
- return err
- })
- return size, err
- }
- func MoveFile(sourcePath, destPath string) error {
- inputFile, err := os.Open(sourcePath)
- if err != nil {
- return fmt.Errorf("Couldn't open source file: %s", err)
- }
- outputFile, err := os.Create(destPath)
- if err != nil {
- inputFile.Close()
- return fmt.Errorf("Couldn't open dest file: %s", err)
- }
- defer outputFile.Close()
- _, err = io.Copy(outputFile, inputFile)
- inputFile.Close()
- if err != nil {
- return fmt.Errorf("Writing to output file failed: %s", err)
- }
- err = os.Remove(sourcePath)
- if err != nil {
- return fmt.Errorf("Failed removing original file: %s", err)
- }
- return nil
- }
- func ReadLine(lineNumber int, path string) string {
- file, err := os.Open(path)
- if err != nil {
- return ""
- }
- fileScanner := bufio.NewScanner(file)
- lineCount := 1
- for fileScanner.Scan() {
- if lineCount == lineNumber {
- return fileScanner.Text()
- }
- lineCount++
- }
- defer file.Close()
- return ""
- }
|