file.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. package file
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "io/fs"
  8. "io/ioutil"
  9. "log"
  10. "mime/multipart"
  11. "os"
  12. "path"
  13. path2 "path"
  14. "path/filepath"
  15. "strconv"
  16. "strings"
  17. "github.com/mholt/archiver/v3"
  18. )
  19. // GetSize get the file size
  20. func GetSize(f multipart.File) (int, error) {
  21. content, err := ioutil.ReadAll(f)
  22. return len(content), err
  23. }
  24. // GetExt get the file ext
  25. func GetExt(fileName string) string {
  26. return path.Ext(fileName)
  27. }
  28. // CheckNotExist check if the file exists
  29. func CheckNotExist(src string) bool {
  30. _, err := os.Stat(src)
  31. return os.IsNotExist(err)
  32. }
  33. // CheckPermission check if the file has permission
  34. func CheckPermission(src string) bool {
  35. _, err := os.Stat(src)
  36. return os.IsPermission(err)
  37. }
  38. // IsNotExistMkDir create a directory if it does not exist
  39. func IsNotExistMkDir(src string) error {
  40. if notExist := CheckNotExist(src); notExist {
  41. if err := MkDir(src); err != nil {
  42. return err
  43. }
  44. }
  45. return nil
  46. }
  47. // MkDir create a directory
  48. func MkDir(src string) error {
  49. err := os.MkdirAll(src, os.ModePerm)
  50. if err != nil {
  51. return err
  52. }
  53. os.Chmod(src, 0o777)
  54. return nil
  55. }
  56. // RMDir remove a directory
  57. func RMDir(src string) error {
  58. err := os.RemoveAll(src)
  59. if err != nil {
  60. return err
  61. }
  62. os.Remove(src)
  63. return nil
  64. }
  65. // Open a file according to a specific mode
  66. func Open(name string, flag int, perm os.FileMode) (*os.File, error) {
  67. f, err := os.OpenFile(name, flag, perm)
  68. if err != nil {
  69. return nil, err
  70. }
  71. return f, nil
  72. }
  73. // MustOpen maximize trying to open the file
  74. func MustOpen(fileName, filePath string) (*os.File, error) {
  75. //dir, err := os.Getwd()
  76. //if err != nil {
  77. // return nil, fmt.Errorf("os.Getwd err: %v", err)
  78. //}
  79. src := filePath
  80. perm := CheckPermission(src)
  81. if perm == true {
  82. return nil, fmt.Errorf("file.CheckPermission Permission denied src: %s", src)
  83. }
  84. err := IsNotExistMkDir(src)
  85. if err != nil {
  86. return nil, fmt.Errorf("file.IsNotExistMkDir src: %s, err: %v", src, err)
  87. }
  88. f, err := Open(src+fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o644)
  89. if err != nil {
  90. return nil, fmt.Errorf("Fail to OpenFile :%v", err)
  91. }
  92. return f, nil
  93. }
  94. // 判断所给路径文件/文件夹是否存在
  95. func Exists(path string) bool {
  96. _, err := os.Stat(path) // os.Stat获取文件信息
  97. if err != nil {
  98. if os.IsExist(err) {
  99. return true
  100. }
  101. return false
  102. }
  103. return true
  104. }
  105. // 判断所给路径是否为文件夹
  106. func IsDir(path string) bool {
  107. s, err := os.Stat(path)
  108. if err != nil {
  109. return false
  110. }
  111. return s.IsDir()
  112. }
  113. // 判断所给路径是否为文件
  114. func IsFile(path string) bool {
  115. return !IsDir(path)
  116. }
  117. func CreateFile(path string) error {
  118. file, err := os.Create(path)
  119. if err != nil {
  120. return err
  121. }
  122. defer file.Close()
  123. return nil
  124. }
  125. func CreateFileAndWriteContent(path string, content string) error {
  126. file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0o666)
  127. if err != nil {
  128. return err
  129. }
  130. defer file.Close()
  131. write := bufio.NewWriter(file)
  132. write.WriteString(content)
  133. write.Flush()
  134. return nil
  135. }
  136. // IsNotExistMkDir create a directory if it does not exist
  137. func IsNotExistCreateFile(src string) error {
  138. if notExist := CheckNotExist(src); notExist {
  139. if err := CreateFile(src); err != nil {
  140. return err
  141. }
  142. }
  143. return nil
  144. }
  145. func ReadFullFile(path string) []byte {
  146. file, err := os.Open(path)
  147. if err != nil {
  148. return []byte("")
  149. }
  150. defer file.Close()
  151. content, err := ioutil.ReadAll(file)
  152. if err != nil {
  153. return []byte("")
  154. }
  155. return content
  156. }
  157. // File copies a single file from src to dst
  158. func CopyFile(src, dst, style string) error {
  159. var err error
  160. var srcfd *os.File
  161. var dstfd *os.File
  162. var srcinfo os.FileInfo
  163. lastPath := src[strings.LastIndex(src, "/")+1:]
  164. if !strings.HasSuffix(dst, "/") {
  165. dst += "/"
  166. }
  167. dst += lastPath
  168. if Exists(dst) {
  169. if style == "skip" {
  170. return nil
  171. } else {
  172. os.Remove(dst)
  173. }
  174. }
  175. if srcfd, err = os.Open(src); err != nil {
  176. return err
  177. }
  178. defer srcfd.Close()
  179. if dstfd, err = os.Create(dst); err != nil {
  180. return err
  181. }
  182. defer dstfd.Close()
  183. if _, err = io.Copy(dstfd, srcfd); err != nil {
  184. return err
  185. }
  186. if srcinfo, err = os.Stat(src); err != nil {
  187. return err
  188. }
  189. return os.Chmod(dst, srcinfo.Mode())
  190. }
  191. /**
  192. * @description:
  193. * @param {*} src
  194. * @param {*} dst
  195. * @param {string} style
  196. * @return {*}
  197. * @method:
  198. * @router:
  199. */
  200. func CopySingleFile(src, dst, style string) error {
  201. var err error
  202. var srcfd *os.File
  203. var dstfd *os.File
  204. var srcinfo os.FileInfo
  205. if Exists(dst) {
  206. if style == "skip" {
  207. return nil
  208. } else {
  209. os.Remove(dst)
  210. }
  211. }
  212. if srcfd, err = os.Open(src); err != nil {
  213. return err
  214. }
  215. defer srcfd.Close()
  216. if dstfd, err = os.Create(dst); err != nil {
  217. return err
  218. }
  219. defer dstfd.Close()
  220. if _, err = io.Copy(dstfd, srcfd); err != nil {
  221. return err
  222. }
  223. if srcinfo, err = os.Stat(src); err != nil {
  224. return err
  225. }
  226. return os.Chmod(dst, srcinfo.Mode())
  227. }
  228. // Check for duplicate file names
  229. func GetNoDuplicateFileName(fullPath string) string {
  230. path, fileName := filepath.Split(fullPath)
  231. fileSuffix := path2.Ext(fileName)
  232. filenameOnly := strings.TrimSuffix(fileName, fileSuffix)
  233. for i := 0; Exists(fullPath); i++ {
  234. fullPath = path2.Join(path, filenameOnly+"("+strconv.Itoa(i+1)+")"+fileSuffix)
  235. }
  236. return fullPath
  237. }
  238. // Dir copies a whole directory recursively
  239. func CopyDir(src string, dst string, style string) error {
  240. var err error
  241. var fds []os.FileInfo
  242. var srcinfo os.FileInfo
  243. if srcinfo, err = os.Stat(src); err != nil {
  244. return err
  245. }
  246. if !srcinfo.IsDir() {
  247. if err = CopyFile(src, dst, style); err != nil {
  248. fmt.Println(err)
  249. }
  250. return nil
  251. }
  252. // dstPath := dst
  253. lastPath := src[strings.LastIndex(src, "/")+1:]
  254. dst += "/" + lastPath
  255. // for i := 0; Exists(dst); i++ {
  256. // dst = dstPath + "/" + lastPath + strconv.Itoa(i+1)
  257. // }
  258. if Exists(dst) {
  259. if style == "skip" {
  260. return nil
  261. } else {
  262. os.Remove(dst)
  263. }
  264. }
  265. if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
  266. return err
  267. }
  268. if fds, err = ioutil.ReadDir(src); err != nil {
  269. return err
  270. }
  271. for _, fd := range fds {
  272. srcfp := path.Join(src, fd.Name())
  273. dstfp := dst // path.Join(dst, fd.Name())
  274. if fd.IsDir() {
  275. if err = CopyDir(srcfp, dstfp, style); err != nil {
  276. fmt.Println(err)
  277. }
  278. } else {
  279. if err = CopyFile(srcfp, dstfp, style); err != nil {
  280. fmt.Println(err)
  281. }
  282. }
  283. }
  284. return nil
  285. }
  286. func WriteToPath(data []byte, path, name string) error {
  287. fullPath := path
  288. if strings.HasSuffix(path, "/") {
  289. fullPath += name
  290. } else {
  291. fullPath += "/" + name
  292. }
  293. return WriteToFullPath(data, fullPath, 0o666)
  294. }
  295. func WriteToFullPath(data []byte, fullPath string, perm fs.FileMode) error {
  296. if err := IsNotExistCreateFile(fullPath); err != nil {
  297. return err
  298. }
  299. file, err := os.OpenFile(fullPath,
  300. os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
  301. perm,
  302. )
  303. if err != nil {
  304. return err
  305. }
  306. defer file.Close()
  307. _, err = file.Write(data)
  308. return err
  309. }
  310. // 最终拼接
  311. func SpliceFiles(dir, path string, length int, startPoint int) error {
  312. fullPath := path
  313. if err := IsNotExistCreateFile(fullPath); err != nil {
  314. return err
  315. }
  316. file, _ := os.OpenFile(fullPath,
  317. os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
  318. 0o666,
  319. )
  320. defer file.Close()
  321. bufferedWriter := bufio.NewWriter(file)
  322. // todo: here should have a goroutine to remove each partial file after it is read, to save disk space
  323. for i := 0; i < length+startPoint; i++ {
  324. data, err := ioutil.ReadFile(dir + "/" + strconv.Itoa(i+startPoint))
  325. if err != nil {
  326. return err
  327. }
  328. if _, err := bufferedWriter.Write(data); err != nil { // recommend to use https://github.com/iceber/iouring-go for faster write
  329. return err
  330. }
  331. }
  332. bufferedWriter.Flush()
  333. return nil
  334. }
  335. func GetCompressionAlgorithm(t string) (string, archiver.Writer, error) {
  336. switch t {
  337. case "zip", "":
  338. return ".zip", archiver.NewZip(), nil
  339. case "tar":
  340. return ".tar", archiver.NewTar(), nil
  341. case "targz":
  342. return ".tar.gz", archiver.NewTarGz(), nil
  343. case "tarbz2":
  344. return ".tar.bz2", archiver.NewTarBz2(), nil
  345. case "tarxz":
  346. return ".tar.xz", archiver.NewTarXz(), nil
  347. case "tarlz4":
  348. return ".tar.lz4", archiver.NewTarLz4(), nil
  349. case "tarsz":
  350. return ".tar.sz", archiver.NewTarSz(), nil
  351. default:
  352. return "", nil, errors.New("format not implemented")
  353. }
  354. }
  355. func AddFile(ar archiver.Writer, path, commonPath string) error {
  356. info, err := os.Stat(path)
  357. if err != nil {
  358. return err
  359. }
  360. if !info.IsDir() && !info.Mode().IsRegular() {
  361. return nil
  362. }
  363. file, err := os.Open(path)
  364. if err != nil {
  365. return err
  366. }
  367. defer file.Close()
  368. if path != commonPath {
  369. filename := info.Name()
  370. err = ar.Write(archiver.File{
  371. FileInfo: archiver.FileInfo{
  372. FileInfo: info,
  373. CustomName: filename,
  374. },
  375. ReadCloser: file,
  376. })
  377. if err != nil {
  378. return err
  379. }
  380. }
  381. if info.IsDir() {
  382. names, err := file.Readdirnames(0)
  383. if err != nil {
  384. return err
  385. }
  386. for _, name := range names {
  387. err = AddFile(ar, filepath.Join(path, name), commonPath)
  388. if err != nil {
  389. log.Printf("Failed to archive %v", err)
  390. }
  391. }
  392. }
  393. return nil
  394. }
  395. func CommonPrefix(sep byte, paths ...string) string {
  396. // Handle special cases.
  397. switch len(paths) {
  398. case 0:
  399. return ""
  400. case 1:
  401. return path.Clean(paths[0])
  402. }
  403. // Note, we treat string as []byte, not []rune as is often
  404. // done in Go. (And sep as byte, not rune). This is because
  405. // most/all supported OS' treat paths as string of non-zero
  406. // bytes. A filename may be displayed as a sequence of Unicode
  407. // runes (typically encoded as UTF-8) but paths are
  408. // not required to be valid UTF-8 or in any normalized form
  409. // (e.g. "é" (U+00C9) and "é" (U+0065,U+0301) are different
  410. // file names.
  411. c := []byte(path.Clean(paths[0]))
  412. // We add a trailing sep to handle the case where the
  413. // common prefix directory is included in the path list
  414. // (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
  415. // path.Clean will have cleaned off trailing / separators with
  416. // the exception of the root directory, "/" (in which case we
  417. // make it "//", but this will get fixed up to "/" bellow).
  418. c = append(c, sep)
  419. // Ignore the first path since it's already in c
  420. for _, v := range paths[1:] {
  421. // Clean up each path before testing it
  422. v = path.Clean(v) + string(sep)
  423. // Find the first non-common byte and truncate c
  424. if len(v) < len(c) {
  425. c = c[:len(v)]
  426. }
  427. for i := 0; i < len(c); i++ {
  428. if v[i] != c[i] {
  429. c = c[:i]
  430. break
  431. }
  432. }
  433. }
  434. // Remove trailing non-separator characters and the final separator
  435. for i := len(c) - 1; i >= 0; i-- {
  436. if c[i] == sep {
  437. c = c[:i]
  438. break
  439. }
  440. }
  441. return string(c)
  442. }
  443. func GetFileOrDirSize(path string) (int64, error) {
  444. fileInfo, err := os.Stat(path)
  445. if err != nil {
  446. return 0, err
  447. }
  448. if fileInfo.IsDir() {
  449. return DirSizeB(path + "/")
  450. }
  451. return fileInfo.Size(), nil
  452. }
  453. // getFileSize get file size by path(B)
  454. func DirSizeB(path string) (int64, error) {
  455. var size int64
  456. err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
  457. if !info.IsDir() {
  458. size += info.Size()
  459. }
  460. return err
  461. })
  462. return size, err
  463. }
  464. func MoveFile(sourcePath, destPath string) error {
  465. inputFile, err := os.Open(sourcePath)
  466. if err != nil {
  467. return fmt.Errorf("Couldn't open source file: %s", err)
  468. }
  469. outputFile, err := os.Create(destPath)
  470. if err != nil {
  471. inputFile.Close()
  472. return fmt.Errorf("Couldn't open dest file: %s", err)
  473. }
  474. defer outputFile.Close()
  475. _, err = io.Copy(outputFile, inputFile)
  476. inputFile.Close()
  477. if err != nil {
  478. return fmt.Errorf("Writing to output file failed: %s", err)
  479. }
  480. err = os.Remove(sourcePath)
  481. if err != nil {
  482. return fmt.Errorf("Failed removing original file: %s", err)
  483. }
  484. return nil
  485. }
  486. func ReadLine(lineNumber int, path string) string {
  487. file, err := os.Open(path)
  488. if err != nil {
  489. return ""
  490. }
  491. fileScanner := bufio.NewScanner(file)
  492. lineCount := 1
  493. for fileScanner.Scan() {
  494. if lineCount == lineNumber {
  495. return fileScanner.Text()
  496. }
  497. lineCount++
  498. }
  499. defer file.Close()
  500. return ""
  501. }