Ai
1 Star 1 Fork 0

bon-ami/eztools

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
files.go 5.69 KB
一键复制 编辑 原始数据 按行查看 历史
Allen Tse 提交于 2023-01-12 15:42 +08:00 . thorough comments and camel names
package eztools
import (
"archive/zip"
"io"
"io/fs"
"mime"
"os"
"path/filepath"
)
const (
// FileCreatePermission 0644
FileCreatePermission = 0644
// DirCreatePermission 0755
DirCreatePermission = 0755
// FileSizeMax2Split size of a file piece
FileSizeMax2Split = 2<<31 - 1
)
// FileReadByPiece reads a file by hunk in a loop
// uint32 is to hold file size, so its max size is 4'294'967'295
// Parameters:
//
// readSz() returns how much to read, every time
// fun() handles the read part, every time, returning whether to stop
//
// Return values:
//
// error from fun()
// ErrIncomplete if the file is zero sized
// ErrOutOfBound if the size of the file is too big
// ErrInvalidInput if the size of the part read does not equal the request
// from os.Stat(), os.OpenFile(), os.File.Seek(), os.File.Read()
func FileReadByPiece(file string, readSz func(indx uint32,
inf fs.FileInfo, done uint32) uint32,
fun func(indx uint32, inf fs.FileInfo, offset uint32,
bytes []byte) error) (err error) {
inf, err := os.Stat(file)
if err != nil {
return
}
if inf.Size() > FileSizeMax2Split {
return ErrOutOfBound
}
sz := uint32(inf.Size())
if sz == 0 {
return ErrIncomplete
}
fp, err := os.OpenFile(file, os.O_RDONLY, FileCreatePermission)
if err != nil {
return
}
defer fp.Close()
var offset, indx uint32
for offset < sz {
sz := readSz(indx, inf, offset)
_, err = fp.Seek(int64(offset), 0)
if err != nil {
return
}
buf := make([]byte, sz)
n, err := fp.Read(buf)
if err != nil {
return err
}
if uint32(n) != sz {
return ErrInvalidInput
}
err = fun(indx, inf, offset, buf)
if err != nil {
return err
}
offset += uint32(sz)
indx++
}
return
}
// FileReaderByPiece reads a file by hunk in a loop
// Parameters:
func FileReaderByPiece(rdr io.ReadCloser, name string, readSz func(indx uint32,
name string) (uint32, string),
fun func(indx uint32, name string,
bytes []byte, done bool) error) (err error) {
defer rdr.Close()
var sz, indx uint32
for {
sz, name = readSz(indx, name)
buf := make([]byte, sz)
n, err := rdr.Read(buf)
if err != nil {
if err == io.EOF {
return fun(indx, name, buf[:n], true)
}
return err
}
done := uint32(n) < sz
err = fun(indx, name, buf[:n], done)
if err != nil || done {
return err
}
indx++
}
}
// FileAppend appends bytes to file
//
// file will be created, if not exists yet, but parent directories cannot be created.
func FileAppend(file string, bytes []byte) (err error) {
f, err := os.OpenFile(file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, FileCreatePermission)
if err != nil {
return
}
defer f.Close()
_, err = f.Write(bytes)
return
}
// FileWrite writes bytes to file
// Return value: from os.WriteFile() or os.MkdirAll(), if failed to creat parent directories
func FileWrite(file string, bytes []byte) error {
path := filepath.Dir(file)
if _, err := os.Stat(path); err != nil {
err = os.MkdirAll(path, DirCreatePermission)
if err != nil {
return err
}
}
return os.WriteFile(file, bytes, FileCreatePermission)
}
// FileWriteNoCreate writes input bytes to existing file
// Return value: from FileWrite() or os.Stat()
func FileWriteNoCreate(file string, bytes []byte) error {
if _, err := os.Stat(file); err != nil {
return err
}
return FileWrite(file, bytes)
}
// FileDel file deletion
func FileDel(fn string) error {
if err := os.Remove(fn); err != nil {
return err
}
parent := filepath.Dir(fn)
f, err := os.Open(parent)
if err != nil {
return nil
}
_, err = f.Readdirnames(1)
if err == nil {
return nil
}
os.Remove(parent)
return nil
}
// FileType returns MIME type of a file by extension
func FileType(fn string) string {
return mime.TypeByExtension(filepath.Ext(fn))
// http.DetectContentType([]byte)
}
// ZipWtReaderWriter zips files iterated by getRd to wr
//
// readers and wr are Close()'ed before returning
// the last reader must be nil to stop iteration
//
// Return value: error to create result file,
// or, error to each file to be packed and to final closure
func ZipWtReaderWriter(getRd func() (string, io.ReadCloser), wr io.WriteCloser) (ret []error) {
defer wr.Close()
zpWr := zip.NewWriter(wr)
for {
fn, fp := getRd()
if fp == nil {
break
}
f, err := zpWr.Create(fn)
if err == nil {
_, err = io.Copy(f, fp)
}
ret = append(ret, err)
// fp.Close()
}
// Make sure to check the error on Close.
return append(ret, zpWr.Close())
}
// ZipWtWriter zips files to wr, with relative directory baseDir
//
// Parameter: baseDir if "", no dir info packed
// Return value: error to create result file,
// or, error to each file to be packed and to final closure
func ZipWtWriter(files []string, baseDir string, wr io.WriteCloser) (ret []error) {
defer wr.Close()
zpWr := zip.NewWriter(wr)
for _, file := range files {
pa, err := func() (string, error) {
if len(baseDir) > 0 {
return filepath.Rel(baseDir, file)
}
return "", ErrIncomplete
}()
if err != nil {
pa = filepath.Base(file)
}
f, err := zpWr.Create(pa)
if err != nil {
ret = append(ret, err)
continue
}
fp, err := os.OpenFile(file, os.O_RDONLY, FileCreatePermission)
if err == nil {
_, err = io.Copy(f, fp)
}
ret = append(ret, err)
fp.Close()
}
// Make sure to check the error on Close.
return append(ret, zpWr.Close())
}
// Zip zips files to zpName, with relative directory baseDir
//
// Parameter: baseDir if "", no dir info packed
// Return value: error to create result file,
// or, error to each file to be packed and to final closure
func Zip(files []string, baseDir, zpName string) (ret []error) {
wr, err := os.OpenFile(zpName,
os.O_TRUNC|os.O_CREATE|os.O_WRONLY, FileCreatePermission)
if err != nil {
return []error{err}
}
return ZipWtWriter(files, baseDir, wr)
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/bon-ami/eztools.git
git@gitee.com:bon-ami/eztools.git
bon-ami
eztools
eztools
v5.0.2

搜索帮助