add file utils
This commit is contained in:
parent
4c1a50cae2
commit
4e5d76af37
314
pkg/fileutil/file.go
Normal file
314
pkg/fileutil/file.go
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
// Package fileutil 实现了一些文件操作的基本功能
|
||||||
|
package fileutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsExist 检查一个文件或目录是否存在
|
||||||
|
func IsExist(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateFile 在路径中创建一个文件
|
||||||
|
func CreateFile(path string) bool {
|
||||||
|
file, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDir 检查路径是否为目录
|
||||||
|
func IsDir(path string) bool {
|
||||||
|
file, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return file.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveFile 删除路径中的文件
|
||||||
|
func RemoveFile(path string) error {
|
||||||
|
return os.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyFile 复制src文件到dest文件
|
||||||
|
func CopyFile(srcFilePath string, dstFilePath string) error {
|
||||||
|
srcFile, err := os.Open(srcFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
distFile, err := os.Create(dstFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer distFile.Close()
|
||||||
|
|
||||||
|
var tmp = make([]byte, 1024*4)
|
||||||
|
for {
|
||||||
|
n, err := srcFile.Read(tmp)
|
||||||
|
distFile.Write(tmp[:n])
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ClearFile 在路径文件中写入空字符串
|
||||||
|
func ClearFile(path string) error {
|
||||||
|
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.WriteString("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//ReadFileToString 返回文件内容的字符串
|
||||||
|
func ReadFileToString(path string) (string, error) {
|
||||||
|
bytes, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadFileByLine 逐行读取文件
|
||||||
|
func ReadFileByLine(path string) ([]string, error) {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
res := make([]string, 0)
|
||||||
|
buf := bufio.NewReader(f)
|
||||||
|
|
||||||
|
for {
|
||||||
|
line, _, err := buf.ReadLine()
|
||||||
|
l := string(line)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res = append(res, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListFileNames 返回路径中的所有文件名
|
||||||
|
func ListFileNames(path string) ([]string, error) {
|
||||||
|
if !IsExist(path) {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fs, err := ioutil.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sz := len(fs)
|
||||||
|
if sz == 0 {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
res := []string{}
|
||||||
|
for i := 0; i < sz; i++ {
|
||||||
|
if !fs[i].IsDir() {
|
||||||
|
res = append(res, fs[i].Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zip 创建压缩文件, 参数`filePath`可以是一个单独的文件或一个目录
|
||||||
|
func Zip(filePath string, destPath string) error {
|
||||||
|
zipFile, err := os.Create(destPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer zipFile.Close()
|
||||||
|
|
||||||
|
archive := zip.NewWriter(zipFile)
|
||||||
|
defer archive.Close()
|
||||||
|
|
||||||
|
filepath.Walk(filePath, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header, err := zip.FileInfoHeader(info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header.Name = strings.TrimPrefix(path, filepath.Dir(filePath)+"/")
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
header.Name += "/"
|
||||||
|
} else {
|
||||||
|
header.Method = zip.Deflate
|
||||||
|
}
|
||||||
|
|
||||||
|
writer, err := archive.CreateHeader(header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !info.IsDir() {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
_, err = io.Copy(writer, file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnZip 解压缩文件并将其保存到destPath
|
||||||
|
func UnZip(zipFile string, destPath string) error {
|
||||||
|
zipReader, err := zip.OpenReader(zipFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer zipReader.Close()
|
||||||
|
|
||||||
|
for _, f := range zipReader.File {
|
||||||
|
path := filepath.Join(destPath, f.Name)
|
||||||
|
if f.FileInfo().IsDir() {
|
||||||
|
os.MkdirAll(path, os.ModePerm)
|
||||||
|
} else {
|
||||||
|
if err = os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
inFile, err := f.Open()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer inFile.Close()
|
||||||
|
|
||||||
|
outFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(outFile, inFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsLink 检查一个文件是否是符号链接
|
||||||
|
func IsLink(path string) bool {
|
||||||
|
fi, err := os.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return fi.Mode()&os.ModeSymlink != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileMode 返回文件的模式和权限
|
||||||
|
func FileMode(path string) (fs.FileMode, error) {
|
||||||
|
fi, err := os.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return fi.Mode(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MiMeType 返回文件的mime类型
|
||||||
|
// 参数 `file`应该是字符串(文件路径)或*os.File
|
||||||
|
func MiMeType(file any) string {
|
||||||
|
var mediatype string
|
||||||
|
|
||||||
|
readBuffer := func(f *os.File) ([]byte, error) {
|
||||||
|
buffer := make([]byte, 512)
|
||||||
|
_, err := f.Read(buffer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buffer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if filePath, ok := file.(string); ok {
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return mediatype
|
||||||
|
}
|
||||||
|
buffer, err := readBuffer(f)
|
||||||
|
if err != nil {
|
||||||
|
return mediatype
|
||||||
|
}
|
||||||
|
return http.DetectContentType(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
if f, ok := file.(*os.File); ok {
|
||||||
|
buffer, err := readBuffer(f)
|
||||||
|
if err != nil {
|
||||||
|
return mediatype
|
||||||
|
}
|
||||||
|
return http.DetectContentType(buffer)
|
||||||
|
}
|
||||||
|
return mediatype
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotExistMkDir 如果不存在则新建文件夹
|
||||||
|
func IsNotExistMkDir(src string) error {
|
||||||
|
if notExist := IsExist(src); !notExist {
|
||||||
|
if err := MkDir(src); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkDir 新建文件夹
|
||||||
|
func MkDir(src string) error {
|
||||||
|
err := os.MkdirAll(src, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
177
pkg/fileutil/file_test.go
Normal file
177
pkg/fileutil/file_test.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package fileutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsExist(t *testing.T) {
|
||||||
|
cases := []string{"./", "./file.go", "./a.txt"}
|
||||||
|
expected := []bool{true, true, false}
|
||||||
|
|
||||||
|
for i := 0; i < len(cases); i++ {
|
||||||
|
actual := IsExist(cases[i])
|
||||||
|
require.Equal(t, expected[i], actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateFile(t *testing.T) {
|
||||||
|
f := "./text.txt"
|
||||||
|
if CreateFile(f) {
|
||||||
|
file, err := os.Open(f)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, f, file.Name())
|
||||||
|
} else {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
os.Remove(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsDir(t *testing.T) {
|
||||||
|
cases := []string{"./", "./a.txt"}
|
||||||
|
expected := []bool{true, false}
|
||||||
|
|
||||||
|
for i := 0; i < len(cases); i++ {
|
||||||
|
actual := IsDir(cases[i])
|
||||||
|
require.Equal(t, expected[i], actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveFile(t *testing.T) {
|
||||||
|
f := "./text.txt"
|
||||||
|
if !IsExist(f) {
|
||||||
|
CreateFile(f)
|
||||||
|
err := RemoveFile(f)
|
||||||
|
require.Nil(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCopyFile(t *testing.T) {
|
||||||
|
srcFile := "./text.txt"
|
||||||
|
CreateFile(srcFile)
|
||||||
|
|
||||||
|
destFile := "./text_copy.txt"
|
||||||
|
|
||||||
|
err := CopyFile(srcFile, destFile)
|
||||||
|
if err != nil {
|
||||||
|
file, err := os.Open(destFile)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, destFile, file.Name())
|
||||||
|
}
|
||||||
|
os.Remove(srcFile)
|
||||||
|
os.Remove(destFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListFileNames(t *testing.T) {
|
||||||
|
filesInPath, err := ListFileNames("./")
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
expected := []string{"file.go", "file_test.go"}
|
||||||
|
require.Equal(t, expected, filesInPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadFileToString(t *testing.T) {
|
||||||
|
path := "./text.txt"
|
||||||
|
CreateFile(path)
|
||||||
|
|
||||||
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
|
f.WriteString("hello world")
|
||||||
|
|
||||||
|
content, _ := ReadFileToString(path)
|
||||||
|
require.Equal(t, "hello world", content)
|
||||||
|
|
||||||
|
os.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClearFile(t *testing.T) {
|
||||||
|
path := "./text.txt"
|
||||||
|
CreateFile(path)
|
||||||
|
|
||||||
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
f.WriteString("hello world")
|
||||||
|
|
||||||
|
err := ClearFile(path)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
content, _ := ReadFileToString(path)
|
||||||
|
require.Equal(t, "", content)
|
||||||
|
|
||||||
|
os.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadFileByLine(t *testing.T) {
|
||||||
|
path := "./text.txt"
|
||||||
|
CreateFile(path)
|
||||||
|
|
||||||
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
|
defer f.Close()
|
||||||
|
f.WriteString("hello\nworld")
|
||||||
|
|
||||||
|
expected := []string{"hello", "world"}
|
||||||
|
actual, _ := ReadFileByLine(path)
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
|
||||||
|
os.Remove(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestZipAndUnZip(t *testing.T) {
|
||||||
|
srcFile := "./text.txt"
|
||||||
|
CreateFile(srcFile)
|
||||||
|
|
||||||
|
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
|
defer file.Close()
|
||||||
|
file.WriteString("hello\nworld")
|
||||||
|
|
||||||
|
zipFile := "./text.zip"
|
||||||
|
err := Zip(srcFile, zipFile)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
unZipPath := "./unzip"
|
||||||
|
err = UnZip(zipFile, unZipPath)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
unZipFile := "./unzip/text.txt"
|
||||||
|
require.Equal(t, true, IsExist(unZipFile))
|
||||||
|
|
||||||
|
os.Remove(srcFile)
|
||||||
|
os.Remove(zipFile)
|
||||||
|
os.RemoveAll(unZipPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileMode(t *testing.T) {
|
||||||
|
srcFile := "./text.txt"
|
||||||
|
CreateFile(srcFile)
|
||||||
|
|
||||||
|
mode, err := FileMode(srcFile)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
t.Log(mode)
|
||||||
|
|
||||||
|
os.Remove(srcFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsLink(t *testing.T) {
|
||||||
|
srcFile := "./text.txt"
|
||||||
|
CreateFile(srcFile)
|
||||||
|
|
||||||
|
linkFile := "./text.link"
|
||||||
|
if !IsExist(linkFile) {
|
||||||
|
_ = os.Symlink(srcFile, linkFile)
|
||||||
|
}
|
||||||
|
require.Equal(t, true, IsLink(linkFile))
|
||||||
|
|
||||||
|
require.Equal(t, false, IsLink("./file.go"))
|
||||||
|
|
||||||
|
os.Remove(srcFile)
|
||||||
|
os.Remove(linkFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMiMeType(t *testing.T) {
|
||||||
|
f, _ := os.Open("./file.go")
|
||||||
|
require.Equal(t, "text/plain; charset=utf-8", MiMeType(f))
|
||||||
|
require.Equal(t, "text/plain; charset=utf-8", MiMeType("./file.go"))
|
||||||
|
}
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package ft
|
|
||||||
|
|
||||||
import "os"
|
|
||||||
|
|
||||||
// Exists 判断所给路径文件/文件夹是否存在
|
|
||||||
func Exists(path string) bool {
|
|
||||||
_, err := os.Stat(path) //os.Stat获取文件信息
|
|
||||||
if err != nil {
|
|
||||||
if os.IsExist(err) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotExistMkDir 如果不存在则新建文件夹
|
|
||||||
func IsNotExistMkDir(src string) error {
|
|
||||||
if notExist := Exists(src); !notExist {
|
|
||||||
if err := MkDir(src); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MkDir 新建文件夹
|
|
||||||
func MkDir(src string) error {
|
|
||||||
err := os.MkdirAll(src, os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user