1 Star 0 Fork 0

zhenyangze / zlib

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
file.go 25.75 KB
一键复制 编辑 原始数据 按行查看 历史
zhenyangze 提交于 2022-10-04 23:27 . master: [feature] update package
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255
package zlib
import (
"archive/tar"
"archive/zip"
"bufio"
"bytes"
"compress/gzip"
"encoding/csv"
"errors"
"fmt"
"io"
"io/ioutil"
"mime"
"net/http"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"time"
)
const (
Separator = string(filepath.Separator)
)
/*
444 r--r--r--
600 rw-------
644 rw-r--r--
666 rw-rw-rw-
700 rwx------
744 rwxr--r--
755 rwxr-xr-x
777 rwxrwxrwx
*/
func Mkdir(path string) error {
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
return err
}
return nil
}
func Remove(path string) error {
return os.RemoveAll(path)
}
func Move(src string, dst string) error {
return os.Rename(src, dst)
}
func IsDir(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
return s.IsDir()
}
// IsFile 是否(某类型)文件,且存在.
// ftype为枚举(FILE_TYPE_ANY、FILE_TYPE_LINK、FILE_TYPE_REGULAR、FILE_TYPE_COMMON),默认FILE_TYPE_ANY;
func IsFile(fpath string, ftype ...LkkFileType) (res bool) {
var t LkkFileType = FILE_TYPE_ANY
if len(ftype) > 0 {
t = ftype[0]
}
var f os.FileInfo
var e error
var musLink, musRegular bool
if t == FILE_TYPE_LINK {
musLink = true
} else if t == FILE_TYPE_REGULAR {
musRegular = true
} else if t == FILE_TYPE_COMMON {
musLink = true
musRegular = true
}
if (!musLink && !musRegular) || musRegular {
f, e := os.Stat(fpath)
if musRegular {
res = (e == nil) && f.Mode().IsRegular()
} else {
res = (e == nil) && !f.IsDir()
}
}
if !res && musLink {
f, e = os.Lstat(fpath)
res = (e == nil) && (f.Mode()&os.ModeSymlink == os.ModeSymlink)
}
return
}
// IsZip 是否zip文件.
func IsZip(fpath string) bool {
ext := ExtName(fpath)
if ext != "zip" {
return false
}
f, err := os.Open(fpath)
if err != nil {
return false
}
defer func() {
_ = f.Close()
}()
buf := make([]byte, 4)
n, err := f.Read(buf)
return err == nil && n == 4 && bytes.Equal(buf, []byte("PK\x03\x04"))
}
// IsExist 路径(文件/目录)是否存在.
func IsExist(fpath string) bool {
_, err := os.Stat(fpath)
return err == nil || os.IsExist(err)
}
// IsLink 是否链接文件(软链接,且存在).
func IsLink(fpath string) bool {
f, err := os.Lstat(fpath)
if err != nil {
return false
}
return f.Mode()&os.ModeSymlink == os.ModeSymlink
}
func Pwd() string {
path, err := os.Getwd()
if err != nil {
return ""
}
return path
}
func Home() (dir string, err error) {
dir = os.Getenv("HOME")
if len(dir) > 0 && dir[0] == '/' && IsDir(dir) {
return dir, nil
}
return "", err
}
func Stat(path string) (os.FileInfo, error) {
return os.Stat(path)
}
func Basename(path string) string {
return filepath.Base(path)
}
func Dir(path string) string {
return filepath.Dir(path)
}
func Ext(path string) string {
ext := filepath.Ext(path)
if p := strings.IndexByte(ext, '?'); p != -1 {
ext = ext[0:p]
}
return ext
}
func ExtName(path string) string {
return strings.TrimLeft(Ext(path), ".")
}
func TempDir(names ...string) string {
tempDir := "/tmp"
if Separator != "/" || !IsDir(tempDir) {
tempDir = os.TempDir()
}
path := tempDir
for _, name := range names {
path += Separator + name
}
return path
}
func Glob(pattern string, onlyNames bool) ([]string, error) {
if list, err := filepath.Glob(pattern); err == nil {
if onlyNames {
array := make([]string, len(list))
for k, v := range list {
array[k] = Basename(v)
}
return array, nil
}
return list, nil
} else {
return nil, err
}
}
func FileGetContent(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", err
}
defer f.Close()
fd, err := ioutil.ReadAll(f)
if err != nil {
return "", nil
}
return string(fd), nil
}
func FilePutContent(path string, content string, isAppend bool) error {
dir := Dir(path)
if !IsDir(dir) {
if err := Mkdir(dir); err != nil {
return err
}
}
flag := os.O_WRONLY | os.O_TRUNC | os.O_CREATE
perm := os.ModePerm
if isAppend {
flag = os.O_CREATE | os.O_RDWR | os.O_APPEND
perm = os.ModeAppend | os.ModePerm
}
f, err := os.OpenFile(path, flag, perm)
if err != nil {
return err
}
defer f.Close()
data := []byte(content)
if n, err := f.Write(data); err != nil {
return err
} else if n < len(data) {
return io.ErrShortWrite
}
return nil
}
// formatPath 格式化路径.
func FormatPath(fpath string) string {
//替换特殊字符
fpath = strings.NewReplacer(`|`, "", `<`, "", `>`, "", `?`, "", `\`, "/").Replace(fpath)
//替换连续斜杠
fpath = RegFormatDir.ReplaceAllString(fpath, "/")
//处理windows路径(带":")
slashPos := strings.Index(fpath, "/")
colonPos := strings.Index(fpath, ":")
if colonPos >= 0 { //路径中存在":"
if slashPos == 0 { //路径以"/"开头
fpath = strings.ReplaceAll(fpath, ":", "")
} else {
front := fpath[0 : colonPos+1]
back := strings.ReplaceAll(fpath[colonPos:], ":", "")
fpath = front + back
}
}
return fpath
}
// formatDir 格式化目录,将"\","//"替换为"/",且以"/"结尾.
func FormatDir(fpath string) string {
if fpath == "" {
return ""
}
fpath = FormatPath(fpath)
return strings.TrimRight(fpath, "/") + "/"
}
// AbsPath 获取绝对路径,path可允许不存在.
func AbsPath(fpath string) string {
fullPath := ""
res, err := filepath.Abs(fpath) // filepath.Abs最终使用到os.Getwd()检查
if err != nil {
fullPath = filepath.Clean(filepath.Join(`/`, fpath))
} else {
fullPath = res
}
return fullPath
}
// Dirname 返回路径中的目录部分,注意空路径或无目录的返回".".
func Dirname(fpath string) string {
return filepath.Dir(fpath)
}
// AppendFile 插入文件内容.
func AppendFile(fpath string, data []byte) error {
if fpath == "" {
return errors.New("[AppendFile] no path provided")
}
var file *os.File
filePerm, err := GetFileMode(fpath)
if err != nil {
// create the file
file, err = os.Create(fpath)
} else {
// open for append
file, err = os.OpenFile(fpath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, filePerm)
}
if err != nil {
// failed to create or open-for-append the file
return err
}
defer func() {
_ = file.Close()
}()
_, err = file.Write(data)
return err
}
// GetFileMode 获取路径的权限模式.
func GetFileMode(fpath string) (os.FileMode, error) {
finfo, err := os.Lstat(fpath)
if err != nil {
return 0, err
}
return finfo.Mode(), nil
}
// ChmodBatch 批量改变路径权限模式(包括子目录和所属文件).
// filemode为文件权限模式,dirmode为目录权限模式.
func ChmodBatch(fpath string, filemode, dirmode os.FileMode) (res bool) {
err := filepath.Walk(fpath, func(fpath string, f os.FileInfo, err error) error {
if f == nil {
return err
}
if f.IsDir() {
err = os.Chmod(fpath, dirmode)
} else {
err = os.Chmod(fpath, filemode)
}
return err
})
if err == nil {
res = true
}
return
}
// CopyFile 拷贝源文件到目标文件,cover为枚举(FILE_COVER_ALLOW、FILE_COVER_IGNORE、FILE_COVER_DENY).
func CopyFile(source string, dest string, cover LkkFileCover) (int64, error) {
if source == dest {
return 0, nil
}
sourceStat, err := os.Stat(source)
if err != nil {
return 0, err
} else if !sourceStat.Mode().IsRegular() {
return 0, fmt.Errorf("[CopyFile]`source %s is not a regular file", source)
}
if cover != FILE_COVER_ALLOW {
if _, err := os.Stat(dest); err == nil {
if cover == FILE_COVER_IGNORE {
return 0, nil
} else if cover == FILE_COVER_DENY {
return 0, fmt.Errorf("[CopyFile]`dest File %s already exists", dest)
}
}
}
sourceFile, _ := os.Open(source)
defer func() {
_ = sourceFile.Close()
}()
//源目录
srcDirStat, _ := os.Stat(filepath.Dir(source))
//创建目录
destDir := filepath.Dir(dest)
if err = os.MkdirAll(destDir, srcDirStat.Mode()); err != nil {
return 0, err
}
destFile, err := os.Create(dest)
if err != nil {
return 0, err
}
defer func() {
_ = destFile.Close()
}()
var nBytes int64
sourceSize := sourceStat.Size()
if sourceSize <= 1048576 { //1M以内小文件使用buffer拷贝
var total int
var bufferSize int = 102400
if sourceSize < 524288 {
bufferSize = 51200
}
buf := make([]byte, bufferSize)
for {
n, err := sourceFile.Read(buf)
if err != nil && err != io.EOF {
return int64(total), err
} else if n == 0 {
break
}
if _, err := destFile.Write(buf[:n]); err != nil || !IsExist(dest) {
return int64(total), err
}
total += n
}
nBytes = int64(total)
} else {
nBytes, err = io.Copy(destFile, sourceFile)
if err == nil {
err = os.Chmod(dest, sourceStat.Mode())
}
}
return nBytes, err
}
// CopyLink 拷贝链接.
func CopyLink(source string, dest string) error {
if source == dest {
return nil
}
source, err := os.Readlink(source)
if err != nil {
return err
}
//移除已存在的目标文件
_, err = os.Lstat(dest)
if err == nil {
_ = os.Remove(dest)
}
//创建目录
destDir := filepath.Dir(dest)
if err := os.MkdirAll(destDir, 0777); err != nil {
return err
}
return os.Symlink(source, dest)
}
// CopyDir 拷贝源目录到目标目录,cover为枚举(FILE_COVER_ALLOW、FILE_COVER_IGNORE、FILE_COVER_DENY).
func CopyDir(source string, dest string, cover LkkFileCover) (int64, error) {
var total, nBytes int64
var err error
if source == "" || source == dest {
return 0, nil
}
sourceInfo, err := os.Stat(source)
if err != nil {
return 0, err
} else if !sourceInfo.IsDir() {
return 0, fmt.Errorf("[CopyDir]`source %s is not a directory", source)
}
// create dest dir
if err = os.MkdirAll(dest, sourceInfo.Mode()); err != nil {
return 0, err
}
directory, _ := os.Open(source)
defer func() {
_ = directory.Close()
}()
objects, err := directory.Readdir(-1)
if err != nil {
return 0, err
}
for _, obj := range objects {
srcFilePath := filepath.Join(source, obj.Name())
destFilePath := filepath.Join(dest, obj.Name())
if obj.IsDir() {
// create sub-directories - recursively
nBytes, err = CopyDir(srcFilePath, destFilePath, cover)
} else {
destFileInfo, err := os.Stat(destFilePath)
if err == nil {
if cover != FILE_COVER_ALLOW || os.SameFile(obj, destFileInfo) {
continue
}
}
if obj.Mode()&os.ModeSymlink != 0 {
// a link
_ = CopyLink(srcFilePath, destFilePath)
} else {
nBytes, err = CopyFile(srcFilePath, destFilePath, cover)
}
}
if err == nil {
total += nBytes
}
}
return total, err
}
// CountLines 统计文件行数.buffLength为缓冲长度,kb.
func CountLines(fpath string, buffLength int) (int, error) {
fh, err := os.Open(fpath)
if err != nil {
return -1, err
}
defer func() {
_ = fh.Close()
}()
count := 0
lineSep := []byte{'\n'}
if buffLength <= 0 {
buffLength = 32
}
r := bufio.NewReader(fh)
buf := make([]byte, buffLength*1024)
for {
c, err := r.Read(buf)
count += bytes.Count(buf[:c], lineSep)
switch {
case err == io.EOF:
return count, nil
case err != nil:
return count, err
}
}
}
// DelDir 删除目录.delete为true时连该目录一起删除;为false时只清空该目录.
func DelDir(dir string, delete bool) error {
realPath := AbsPath(dir)
if !IsDir(realPath) {
return fmt.Errorf("[DelDir]`dir %s not exists", dir)
}
names, err := os.ReadDir(realPath)
if err != nil {
return err
}
for _, entery := range names {
file := path.Join([]string{realPath, entery.Name()}...)
err = os.RemoveAll(file)
}
//删除目录
if delete {
err = os.RemoveAll(realPath)
}
return err
}
// FileSize 获取文件大小(bytes字节);注意:文件不存在或无法访问时返回-1 .
func FileSize(fpath string) int64 {
f, err := os.Stat(fpath)
if nil != err {
return -1
}
return f.Size()
}
// DirSize 获取目录大小(bytes字节).
func DirSize(fpath string) int64 {
var size int64
//filepath.Walk压测很慢
_ = filepath.Walk(fpath, func(_ string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
size += info.Size()
}
return err
})
return size
}
// FileTree 获取目录的文件树列表.
// ftype为枚举(FILE_TREE_ALL、FILE_TREE_DIR、FILE_TREE_FILE);
// recursive为是否递归;
// filters为一个或多个文件过滤器函数,FileFilter类型.
func FileTree(fpath string, ftype LkkFileTree, recursive bool, filters ...FileFilter) []string {
var trees []string
if IsFile(fpath, FILE_TYPE_ANY) {
if ftype != FILE_TREE_DIR {
trees = append(trees, fpath)
}
return trees
}
fpath = strings.TrimRight(fpath, "/\\")
files, err := filepath.Glob(filepath.Join(fpath, "*"))
if err != nil || len(files) == 0 {
return trees
}
for _, file := range files {
file = strings.ReplaceAll(file, "\\", "/")
if IsDir(file) {
if ftype != FILE_TREE_FILE {
trees = append(trees, file)
}
if recursive {
subs := FileTree(file, ftype, recursive, filters...)
trees = append(trees, subs...)
}
} else if ftype != FILE_TREE_DIR {
//文件过滤
chk := true
if len(filters) > 0 {
for _, filter := range filters {
chk = filter(file)
if !chk {
break
}
}
}
if !chk {
continue
}
trees = append(trees, file)
}
}
return trees
}
// GetMime 获取文件mime类型;fast为true时根据后缀快速获取;为false时读取文件头获取.
func GetMime(fpath string, fast bool) string {
var res string
if fast {
suffix := ExtName(fpath)
//当unix系统中没有相关的mime.types文件时,将返回空
res = mime.TypeByExtension(suffix)
} else {
srcFile, err := os.Open(fpath)
if err != nil {
return res
}
buffer := make([]byte, 512)
_, err = srcFile.Read(buffer)
if err != nil {
return res
}
res = http.DetectContentType(buffer)
}
return res
}
// GetModTime 获取文件的修改时间戳,秒.
func GetModTime(fpath string) (res int64) {
fileinfo, err := os.Stat(fpath)
if err == nil {
res = fileinfo.ModTime().Unix()
}
return
}
// IsBinary 是否二进制文件(且存在).
func IsBinaryFile(fpath string) bool {
cont, err := ReadFile(fpath)
if err != nil {
return false
}
return IsBinary(string(cont))
}
// IsImg 是否图片文件(仅检查后缀).
func IsImg(fpath string) bool {
ext := ExtName(fpath)
if InArray(ext, ImageExtList) {
return true
}
return false
}
// ReadFile 读取文件内容.
func ReadFile(fpath string) ([]byte, error) {
data, err := os.ReadFile(fpath)
return data, err
}
// ReadInArray 把整个文件读入一个数组中,每行作为一个元素.
func ReadInArray(fpath string) ([]string, error) {
data, err := os.ReadFile(fpath)
if err != nil {
return nil, err
}
return strings.Split(string(data), "\n"), nil
}
// ReadFirstLine 读取文件首行.
func ReadFirstLine(fpath string) []byte {
var res []byte
fh, err := os.Open(fpath)
if err == nil {
scanner := bufio.NewScanner(fh)
for scanner.Scan() {
res = scanner.Bytes()
break
}
}
defer func() {
_ = fh.Close()
}()
return res
}
// ReadLastLine 读取文件末行.
func ReadLastLine(fpath string) []byte {
var res []byte
fh, err := os.Open(fpath)
if err == nil {
var lastLineSize int
reader := bufio.NewReader(fh)
for {
bs, err := reader.ReadBytes('\n')
lastLineSize = len(bs)
if err == io.EOF {
break
}
}
fileInfo, _ := os.Stat(fpath)
// make a buffer size according to the lastLineSize
buffer := make([]byte, lastLineSize)
offset := fileInfo.Size() - int64(lastLineSize)
numRead, _ := fh.ReadAt(buffer, offset)
res = buffer[:numRead]
}
defer func() {
_ = fh.Close()
}()
return res
}
// Pathinfo 获取文件路径的信息.
// option为要返回的信息,枚举值如下:
// -1: all; 1: dirname; 2: basename; 4: extension; 8: filename;
// 若要查看某几项,则为它们之间的和.
func Pathinfo(fpath string, option int) map[string]string {
if option == -1 {
option = 1 | 2 | 4 | 8
}
res := make(map[string]string)
if (option & 1) == 1 {
res["dirname"] = filepath.Dir(fpath)
}
if (option & 2) == 2 {
res["basename"] = filepath.Base(fpath)
}
if ((option & 4) == 4) || ((option & 8) == 8) {
basename := ""
if (option & 2) == 2 {
basename = res["basename"]
} else {
basename = filepath.Base(fpath)
}
p := strings.LastIndex(basename, ".")
filename, extension := "", ""
if p > 0 {
filename, extension = basename[:p], basename[p+1:]
} else if p == -1 {
filename = basename
} else if p == 0 {
extension = basename[p+1:]
}
if (option & 4) == 4 {
res["extension"] = extension
}
if (option & 8) == 8 {
res["filename"] = filename
}
}
return res
}
// RealPath 返回规范化的真实绝对路径名.path必须存在,若路径不存在则返回空字符串.
func RealPath(fpath string) string {
fullPath := fpath
if !filepath.IsAbs(fpath) {
wd, err := os.Getwd()
if err != nil {
return ""
}
fullPath = filepath.Clean(wd + `/` + fpath)
}
_, err := os.Stat(fullPath)
if err != nil {
return ""
}
return fullPath
}
// Rename 重命名(或移动)文件/目录.
func Rename(oldname, newname string) error {
return os.Rename(oldname, newname)
}
// Unlink 删除文件.
func Unlink(fpath string) error {
return os.Remove(fpath)
}
// SafeFileName 将文件名转换为安全可用的字符串.
func SafeFileName(str string) string {
name := path.Clean(path.Base(str))
name = strings.Trim(name, " ")
separators, err := regexp.Compile(`[ &_=+:]`)
if err == nil {
name = separators.ReplaceAllString(name, "-")
}
legal, err := regexp.Compile(`[^[:alnum:]-.]`)
if err == nil {
name = legal.ReplaceAllString(name, "")
}
for strings.Contains(name, "--") {
name = strings.Replace(name, "--", "-", -1)
}
return name
}
// TarGz 打包压缩tar.gz.
// src为源文件或目录,dstTar为打包的路径名,ignorePatterns为要忽略的文件正则.
func TarGz(src string, dstTar string, ignorePatterns ...string) (bool, error) {
//过滤器,检查要忽略的文件
var filter = func(file string) bool {
res := true
for _, pattern := range ignorePatterns {
re, err := regexp.Compile(pattern)
if err != nil {
continue
}
chk := re.MatchString(file)
if chk {
res = false
break
}
}
return res
}
src = AbsPath(src)
dstTar = AbsPath(dstTar)
dstDir := Dirname(dstTar)
if !IsDir(dstDir) {
err := os.MkdirAll(dstDir, os.ModePerm)
if err != nil {
return false, err
}
}
files := FileTree(src, FILE_TREE_ALL, true, filter)
if len(files) == 0 {
return false, fmt.Errorf("[TarGz]`src no files to tar.gz")
}
// dest file write
fw, err := os.Create(dstTar)
if err != nil {
return false, err
}
defer func() {
_ = fw.Close()
}()
// gzip write
gw := gzip.NewWriter(fw)
defer func() {
_ = gw.Close()
}()
// tar write
tw := tar.NewWriter(gw)
defer func() {
_ = tw.Close()
}()
parentDir := filepath.Dir(src)
for _, file := range files {
if file == dstTar {
continue
}
fi, err := os.Stat(file)
if err != nil {
continue
}
newName := strings.Replace(file, parentDir, "", -1)
newName = strings.ReplaceAll(newName, ":", "") //防止wins下 tmp/D: 创建失败
// Create tar header
hdr := new(tar.Header)
hdr.Format = tar.FormatGNU
if fi.IsDir() {
// if last character of header name is '/' it also can be directory
// but if you don't set Typeflag, error will occur when you untargz
hdr.Name = newName + "/"
hdr.Typeflag = tar.TypeDir
hdr.Size = 0
//hdr.Mode = 0755 | c_ISDIR
hdr.Mode = int64(fi.Mode())
hdr.ModTime = fi.ModTime()
// Write hander
err := tw.WriteHeader(hdr)
if err != nil {
return false, fmt.Errorf("[TarGz] DirErr: %s file:%s\n", err.Error(), file)
}
} else {
// File reader
fr, err := os.Open(file)
if err != nil {
return false, fmt.Errorf("[TarGz] OpenErr: %s file:%s\n", err.Error(), file)
}
defer func() {
_ = fr.Close()
}()
hdr.Name = newName
hdr.Size = fi.Size()
hdr.Mode = int64(fi.Mode())
hdr.ModTime = fi.ModTime()
// Write hander
err = tw.WriteHeader(hdr)
if err != nil {
return false, fmt.Errorf("[TarGz] FileErr: %s file:%s\n", err.Error(), file)
}
// Write file data
_, err = io.Copy(tw, fr)
if err != nil {
return false, fmt.Errorf("[TarGz] CopyErr: %s file:%s\n", err.Error(), file)
}
_ = fr.Close()
}
}
return true, nil
}
// UnTarGz 将tar.gz文件解压缩.
// srcTar为压缩包,dstDir为解压目录.
func UnTarGz(srcTar, dstDir string) (bool, error) {
fr, err := os.Open(srcTar)
if err != nil {
return false, err
}
defer func() {
_ = fr.Close()
}()
dstDir = strings.TrimRight(AbsPath(dstDir), "/\\")
if !IsDir(dstDir) {
err := os.MkdirAll(dstDir, os.ModePerm)
if err != nil {
return false, err
}
}
// Gzip reader
gr, err := gzip.NewReader(fr)
if err != nil {
return false, err
}
// Tar reader
tr := tar.NewReader(gr)
for {
hdr, err := tr.Next()
if err == io.EOF {
// End of tar archive
break
} else if err != nil {
return false, err
}
// Create diretory before create file
newPath := dstDir + "/" + strings.TrimLeft(hdr.Name, "/\\")
parentDir := path.Dir(newPath)
if !IsDir(parentDir) {
err := os.MkdirAll(parentDir, os.ModePerm)
if err != nil {
return false, err
}
}
if hdr.Typeflag != tar.TypeDir {
// Write data to file
fw, err := os.Create(newPath)
if err != nil {
return false, fmt.Errorf("[UnTarGz] CreateErr: %s file:%s\n", err.Error(), newPath)
}
_, err = io.Copy(fw, tr)
if err != nil {
return false, fmt.Errorf("[UnTarGz] CopyErr: %s file:%s\n", err.Error(), newPath)
}
_ = fw.Close()
}
}
return true, nil
}
// Touch 快速创建指定大小的文件,size为字节.
func Touch(fpath string, size int64) bool {
//创建目录
destDir := filepath.Dir(fpath)
if err := os.MkdirAll(destDir, 0777); err != nil {
return false
}
fd, err := os.OpenFile(fpath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
if err != nil {
return false
}
defer func() {
_ = fd.Close()
}()
if size > 1 {
_, _ = fd.Seek(size-1, 0)
_, _ = fd.Write([]byte{0})
}
return true
}
// Zip 将文件或目录进行zip打包.fpaths为源文件或目录的路径.
func Zip(dst string, fpaths ...string) (bool, error) {
dst = AbsPath(dst)
dstDir := Dirname(dst)
if !IsDir(dstDir) {
err := os.MkdirAll(dstDir, os.ModePerm)
if err != nil {
return false, err
}
}
fzip, err := os.Create(dst)
if err != nil {
return false, err
}
defer func() {
_ = fzip.Close()
}()
if len(fpaths) == 0 {
return false, errors.New("[Zip] no input files.")
}
var allfiles, files []string
var fpath string
for _, fpath = range fpaths {
if IsDir(fpath) {
files = FileTree(fpath, FILE_TREE_FILE, true)
if len(files) != 0 {
allfiles = append(allfiles, files...)
}
} else if fpath != "" {
allfiles = append(allfiles, fpath)
}
}
if len(allfiles) == 0 {
return false, errors.New("[Zip] no exist files.")
}
zipw := zip.NewWriter(fzip)
defer func() {
_ = zipw.Close()
}()
keys := make(map[string]bool)
for _, fpath = range allfiles {
if _, ok := keys[fpath]; ok || AbsPath(fpath) == dst {
continue
}
fileToZip, err := os.Open(fpath)
if err != nil {
return false, fmt.Errorf("[Zip] failed to open %s: %s", fpath, err)
}
defer func() {
_ = fileToZip.Close()
}()
wr, _ := zipw.Create(fpath)
keys[fpath] = true
if _, err := io.Copy(wr, fileToZip); err != nil {
return false, fmt.Errorf("[Zip] failed to write %s to zip: %s", fpath, err)
}
}
return true, nil
}
// UnZip 解压zip文件.srcZip为zip文件路径,dstDir为解压目录.
func UnZip(srcZip, dstDir string) (bool, error) {
reader, err := zip.OpenReader(srcZip)
if err != nil {
return false, err
}
defer func() {
_ = reader.Close()
}()
dstDir = strings.TrimRight(AbsPath(dstDir), "/\\")
if !IsDir(dstDir) {
err := os.MkdirAll(dstDir, os.ModePerm)
if err != nil {
return false, err
}
}
// 迭代压缩文件中的文件
for _, f := range reader.File {
// Create diretory before create file
//newPath := dstDir + string(os.PathSeparator) + strings.TrimLeft(f.Name, string(os.PathSeparator))
newPath := dstDir + "/" + strings.TrimLeft(f.Name, "/\\")
parentDir := path.Dir(newPath)
if !IsDir(parentDir) {
err := os.MkdirAll(parentDir, os.ModePerm)
if err != nil {
return false, err
}
}
if !f.FileInfo().IsDir() {
if fcreate, err := os.Create(newPath); err == nil {
if rc, err := f.Open(); err == nil {
_, _ = io.Copy(fcreate, rc)
_ = rc.Close() //不要用defer来关闭,如果文件太多的话,会报too many open files 的错误
_ = fcreate.Close()
} else {
_ = fcreate.Close()
return false, err
}
} else {
return false, err
}
}
}
return true, nil
}
// ShaX 计算文件的 shaX 散列值,x为1/256/512.
func GetFileShaX(fpath string, x uint16) (string, error) {
data, err := os.ReadFile(fpath)
if err != nil {
return "", err
}
return string(ShaXByte(data, x)), nil
}
func FileGetCSV(filenameOrURL string, timeout ...time.Duration) ([][]string, error) {
data, err := FileGetBytes(filenameOrURL, timeout...)
if err != nil {
return nil, err
}
reader := csv.NewReader(bytes.NewBuffer(data))
return reader.ReadAll()
}
func FileSetCSV(filename string, records [][]string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close() //#nosec G307
writer := csv.NewWriter(file)
return writer.WriteAll(records)
}
func FileGetBytes(filenameOrURL string, timeout ...time.Duration) ([]byte, error) {
if strings.Contains(filenameOrURL, "://") {
if strings.Index(filenameOrURL, "file://") == 0 {
filenameOrURL = filenameOrURL[len("file://"):]
} else {
client := http.DefaultClient
if len(timeout) > 0 {
client = &http.Client{Timeout: timeout[0]}
}
r, err := client.Get(filenameOrURL)
if err != nil {
return nil, err
}
defer r.Body.Close()
if r.StatusCode < 200 || r.StatusCode > 299 {
return nil, fmt.Errorf("%d: %s", r.StatusCode, http.StatusText(r.StatusCode))
}
return ioutil.ReadAll(r.Body)
}
}
return ioutil.ReadFile(filenameOrURL) //#nosec G304
}
func FileSetBytes(filename string, data []byte) error {
return ioutil.WriteFile(filename, data, 0600)
}
1
https://gitee.com/zhenyangze/zlib.git
git@gitee.com:zhenyangze/zlib.git
zhenyangze
zlib
zlib
v1.0.2

搜索帮助