v1.0.7
This commit is contained in:
兔子
2023-04-12 17:07:16 +08:00
parent 09c82c311b
commit c699bc7d0c
4 changed files with 335 additions and 31 deletions

View File

@@ -1,13 +1,22 @@
package utils
import (
"bufio"
"errors"
"github.com/spf13/cast"
"io"
"os"
"path/filepath"
"sync"
)
// FileStruct - File 结构体
type FileStruct struct {
request *FileRequest
response *FileResponse
}
// FileRequest - File 请求
type FileRequest struct {
// 文件名
Name string
@@ -17,27 +26,37 @@ type FileRequest struct {
Dir string
// 文件后缀
Ext string
// 限制行数
Limit int
// 读取偏移量
Page int
}
// FileStruct - File 结构体
type FileStruct struct {
request *FileRequest
response *FileResponse
}
// FileResponse - File 响应
type FileResponse struct {
Error error
Result string
Result any
Text string
Byte []byte
Slice []any
}
// File - 文件系统
func File(request ...FileRequest) *FileStruct {
if len(request) == 0 {
request = append(request, FileRequest{})
}
if IsEmpty(request[0].Limit) {
request[0].Limit = 10
}
if IsEmpty(request[0].Page) {
request[0].Page = 1
}
return &FileStruct{
request : &request[0],
response: &FileResponse{},
@@ -68,6 +87,18 @@ func (this *FileStruct) Ext(ext any) *FileStruct {
return this
}
// Limit 设置限制行数
func (this *FileStruct) Limit(limit any) *FileStruct {
this.request.Limit = cast.ToInt(limit)
return this
}
// Page 设置读取偏移量
func (this *FileStruct) Page(page any) *FileStruct {
this.request.Page = cast.ToInt(page)
return this
}
// Save 保存文件
func (this *FileStruct) Save(reader io.Reader, path ...string) (result *FileResponse) {
@@ -80,9 +111,7 @@ func (this *FileStruct) Save(reader io.Reader, path ...string) (result *FileResp
return this.response
}
filePath := cast.ToString(path)
dir := filepath.Dir(filePath)
dir := filepath.Dir(this.request.Path)
if _, err := os.Stat(dir); os.IsNotExist(err) {
// 目录不存在,需要创建
if err := os.MkdirAll(dir, 0755); err != nil {
@@ -92,7 +121,7 @@ func (this *FileStruct) Save(reader io.Reader, path ...string) (result *FileResp
}
// 创建文件
file, err := os.Create(filePath)
file, err := os.Create(this.request.Path)
if err != nil {
this.response.Error = err
return this.response
@@ -114,7 +143,7 @@ func (this *FileStruct) Save(reader io.Reader, path ...string) (result *FileResp
return this.response
}
return nil
return this.response
}
// Byte 获取文件字节
@@ -142,33 +171,51 @@ func (this *FileStruct) Byte(path ...any) (result *FileResponse) {
}
}(file)
// // 获取文件大小
// info, _ := file.Stat()
// size := info.Size()
// // 读取文件
// data := make([]byte, size)
// file.Read(data)
// return data
// 获取文件信息
info, err := file.Stat()
if err != nil {
this.response.Error = err
return this.response
}
size := info.Size()
var bytes []byte
// 分批次读取
buf := make([]byte, 1024)
for {
line, err := file.Read(buf)
// 小于50MB整体读取
if size < 50 * 1024 * 1024 {
bytes := make([]byte, size)
_, err = file.Read(bytes)
if err != nil {
this.response.Error = err
return this.response
}
this.response.Byte = bytes
this.response.Text = string(bytes)
this.response.Result = bytes
return this.response
}
// 大于等于50MB分块读取
var bytes []byte
buffer := make([]byte, 1024 * 1024)
for {
index, err := file.Read(buffer)
if err != nil && err != io.EOF {
this.response.Error = err
break
}
bytes = append(bytes, buffer[:index]...)
if err == io.EOF {
break
}
bytes = append(bytes, buf[:line]...)
}
this.response.Byte = bytes
this.response.Result = string(bytes)
this.response.Text = string(bytes)
this.response.Result = bytes
return this.response
}
// FileList 获取指定目录下的所有文件
// List 获取指定目录下的所有文件
func (this *FileStruct) List(opt ...map[string]any) (result *FileResponse) {
// 默认参数
@@ -243,5 +290,121 @@ func (this *FileStruct) List(opt ...map[string]any) (result *FileResponse) {
}
this.response.Slice = cast.ToSlice(slice)
return this.response
}
// IsExist 判断文件是否存在
func (this *FileStruct) IsExist(path ...any) (ok bool) {
if len(path) != 0 {
this.request.Path = cast.ToString(path[0])
}
if IsEmpty(this.request.Path) {
return false
}
// 判断文件是否存在
if _, err := os.Stat(this.request.Path); os.IsNotExist(err) {
return false
}
return true
}
// Line 按行读取文件
func (this *FileStruct) Line(path ...any) (result *FileResponse) {
if len(path) != 0 {
this.request.Path = cast.ToString(path[0])
}
if IsEmpty(this.request.Path) {
this.response.Error = errors.New("文件路径不能为空")
return this.response
}
// 读取块
readBlock := func(file *os.File, start int, end int) ([]string, error) {
lines := make([]string, 0)
scanner := bufio.NewScanner(file)
// 移动扫描器到指定的起始行
for i := 1; i < start && scanner.Scan(); i++ {}
// 开始读取需要的行
for i := start; i <= end && scanner.Scan(); i++ {
// 只把需要的行保存到切片中
if i >= start && i <= end {
lines = append(lines, scanner.Text())
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
return lines, nil
}
file, err := os.Open(this.request.Path)
if err != nil {
this.response.Error = err
return this.response
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
return
}
}(file)
end := this.request.Page * this.request.Limit
start := end - this.request.Limit + 1
lines := make([]string, 0)
// 计算每个块的大小以10MB为一个块
blockSize := 10 * 1024 * 1024
numBlocks := (end - start + 1) / blockSize
if (end - start + 1) % blockSize != 0 {
numBlocks++
}
// 并发读取每个块
var wg sync.WaitGroup
wg.Add(numBlocks)
for i := 0; i < numBlocks; i++ {
go func(i int) {
startLine := start + i * blockSize
endLine := startLine + blockSize - 1
if endLine > end {
endLine = end
}
blockLines, err := readBlock(file, startLine, endLine)
if err != nil {
this.response.Error = err
return
} else {
lines = append(lines, blockLines...)
}
wg.Done()
}(i)
}
wg.Wait()
this.response.Result = lines
this.response.Text = JsonEncode(this.response.Result)
this.response.Byte = []byte(this.response.Text)
for _, v := range lines {
this.response.Slice = append(this.response.Slice, v)
}
return this.response
}