mirror of
https://github.com/unti-io/go-utils.git
synced 2025-09-27 12:42:24 +08:00
v1.0.7
v1.0.7
This commit is contained in:
41
main.go
41
main.go
@@ -2,4 +2,45 @@ package main
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
// // 读取图片文件
|
||||||
|
// file, err := os.Open("input.jpg")
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// defer file.Close()
|
||||||
|
//
|
||||||
|
// // 解码图片
|
||||||
|
// img, _, err := image.Decode(file)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 创建输出文件
|
||||||
|
// out, err := os.Create("output.jpg")
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// defer out.Close()
|
||||||
|
//
|
||||||
|
// // 压缩图片并写入输出文件
|
||||||
|
// opts := jpeg.Options{Quality: 50} // 调整图片质量
|
||||||
|
// err = jpeg.Encode(out, img, &opts)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fmt.Println("图片已成功压缩!")
|
||||||
|
|
||||||
|
// item := utils.File().Page(2).Limit(10).Line(dir + "\\text.log")
|
||||||
|
//
|
||||||
|
// if item.Error != nil {
|
||||||
|
// fmt.Println(item.Error)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for key, val := range item.Slice {
|
||||||
|
// fmt.Println(key + 1, val)
|
||||||
|
// }
|
||||||
}
|
}
|
100
text.log
Normal file
100
text.log
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
这是第 01行 内容
|
||||||
|
这是第 02行 内容
|
||||||
|
这是第 03行 内容
|
||||||
|
这是第 04行 内容
|
||||||
|
这是第 05行 内容
|
||||||
|
这是第 06行 内容
|
||||||
|
这是第 07行 内容
|
||||||
|
这是第 08行 内容
|
||||||
|
这是第 09行 内容
|
||||||
|
这是第 10行 内容
|
||||||
|
这是第 11行 内容
|
||||||
|
这是第 12行 内容
|
||||||
|
这是第 13行 内容
|
||||||
|
这是第 14行 内容
|
||||||
|
这是第 15行 内容
|
||||||
|
这是第 16行 内容
|
||||||
|
这是第 17行 内容
|
||||||
|
这是第 18行 内容
|
||||||
|
这是第 19行 内容
|
||||||
|
这是第 20行 内容
|
||||||
|
这是第 21行 内容
|
||||||
|
这是第 22行 内容
|
||||||
|
这是第 23行 内容
|
||||||
|
这是第 24行 内容
|
||||||
|
这是第 25行 内容
|
||||||
|
这是第 26行 内容
|
||||||
|
这是第 27行 内容
|
||||||
|
这是第 28行 内容
|
||||||
|
这是第 29行 内容
|
||||||
|
这是第 30行 内容
|
||||||
|
这是第 31行 内容
|
||||||
|
这是第 32行 内容
|
||||||
|
这是第 33行 内容
|
||||||
|
这是第 34行 内容
|
||||||
|
这是第 35行 内容
|
||||||
|
这是第 36行 内容
|
||||||
|
这是第 37行 内容
|
||||||
|
这是第 38行 内容
|
||||||
|
这是第 39行 内容
|
||||||
|
这是第 40行 内容
|
||||||
|
这是第 41行 内容
|
||||||
|
这是第 42行 内容
|
||||||
|
这是第 43行 内容
|
||||||
|
这是第 44行 内容
|
||||||
|
这是第 45行 内容
|
||||||
|
这是第 46行 内容
|
||||||
|
这是第 47行 内容
|
||||||
|
这是第 48行 内容
|
||||||
|
这是第 49行 内容
|
||||||
|
这是第 50行 内容
|
||||||
|
这是第 51行 内容
|
||||||
|
这是第 52行 内容
|
||||||
|
这是第 53行 内容
|
||||||
|
这是第 54行 内容
|
||||||
|
这是第 55行 内容
|
||||||
|
这是第 56行 内容
|
||||||
|
这是第 57行 内容
|
||||||
|
这是第 58行 内容
|
||||||
|
这是第 59行 内容
|
||||||
|
这是第 60行 内容
|
||||||
|
这是第 61行 内容
|
||||||
|
这是第 62行 内容
|
||||||
|
这是第 63行 内容
|
||||||
|
这是第 64行 内容
|
||||||
|
这是第 65行 内容
|
||||||
|
这是第 66行 内容
|
||||||
|
这是第 67行 内容
|
||||||
|
这是第 68行 内容
|
||||||
|
这是第 69行 内容
|
||||||
|
这是第 70行 内容
|
||||||
|
这是第 71行 内容
|
||||||
|
这是第 72行 内容
|
||||||
|
这是第 73行 内容
|
||||||
|
这是第 74行 内容
|
||||||
|
这是第 75行 内容
|
||||||
|
这是第 76行 内容
|
||||||
|
这是第 77行 内容
|
||||||
|
这是第 78行 内容
|
||||||
|
这是第 79行 内容
|
||||||
|
这是第 80行 内容
|
||||||
|
这是第 81行 内容
|
||||||
|
这是第 82行 内容
|
||||||
|
这是第 83行 内容
|
||||||
|
这是第 84行 内容
|
||||||
|
这是第 85行 内容
|
||||||
|
这是第 86行 内容
|
||||||
|
这是第 87行 内容
|
||||||
|
这是第 88行 内容
|
||||||
|
这是第 89行 内容
|
||||||
|
这是第 90行 内容
|
||||||
|
这是第 91行 内容
|
||||||
|
这是第 92行 内容
|
||||||
|
这是第 93行 内容
|
||||||
|
这是第 94行 内容
|
||||||
|
这是第 95行 内容
|
||||||
|
这是第 96行 内容
|
||||||
|
这是第 97行 内容
|
||||||
|
这是第 98行 内容
|
||||||
|
这是第 99行 内容
|
||||||
|
这是第 100行 内容
|
221
utils/file.go
221
utils/file.go
@@ -1,13 +1,22 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FileStruct - File 结构体
|
||||||
|
type FileStruct struct {
|
||||||
|
request *FileRequest
|
||||||
|
response *FileResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileRequest - File 请求
|
||||||
type FileRequest struct {
|
type FileRequest struct {
|
||||||
// 文件名
|
// 文件名
|
||||||
Name string
|
Name string
|
||||||
@@ -17,27 +26,37 @@ type FileRequest struct {
|
|||||||
Dir string
|
Dir string
|
||||||
// 文件后缀
|
// 文件后缀
|
||||||
Ext string
|
Ext string
|
||||||
|
// 限制行数
|
||||||
|
Limit int
|
||||||
|
// 读取偏移量
|
||||||
|
Page int
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileStruct - File 结构体
|
// FileResponse - File 响应
|
||||||
type FileStruct struct {
|
|
||||||
request *FileRequest
|
|
||||||
response *FileResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
type FileResponse struct {
|
type FileResponse struct {
|
||||||
Error error
|
Error error
|
||||||
Result string
|
Result any
|
||||||
|
Text string
|
||||||
Byte []byte
|
Byte []byte
|
||||||
Slice []any
|
Slice []any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// File - 文件系统
|
||||||
func File(request ...FileRequest) *FileStruct {
|
func File(request ...FileRequest) *FileStruct {
|
||||||
|
|
||||||
if len(request) == 0 {
|
if len(request) == 0 {
|
||||||
request = append(request, FileRequest{})
|
request = append(request, FileRequest{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if IsEmpty(request[0].Limit) {
|
||||||
|
request[0].Limit = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsEmpty(request[0].Page) {
|
||||||
|
request[0].Page = 1
|
||||||
|
}
|
||||||
|
|
||||||
return &FileStruct{
|
return &FileStruct{
|
||||||
request : &request[0],
|
request : &request[0],
|
||||||
response: &FileResponse{},
|
response: &FileResponse{},
|
||||||
@@ -68,6 +87,18 @@ func (this *FileStruct) Ext(ext any) *FileStruct {
|
|||||||
return this
|
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 保存文件
|
// Save 保存文件
|
||||||
func (this *FileStruct) Save(reader io.Reader, path ...string) (result *FileResponse) {
|
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
|
return this.response
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath := cast.ToString(path)
|
dir := filepath.Dir(this.request.Path)
|
||||||
|
|
||||||
dir := filepath.Dir(filePath)
|
|
||||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||||
// 目录不存在,需要创建
|
// 目录不存在,需要创建
|
||||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
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 {
|
if err != nil {
|
||||||
this.response.Error = err
|
this.response.Error = err
|
||||||
return this.response
|
return this.response
|
||||||
@@ -114,7 +143,7 @@ func (this *FileStruct) Save(reader io.Reader, path ...string) (result *FileResp
|
|||||||
return this.response
|
return this.response
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return this.response
|
||||||
}
|
}
|
||||||
|
|
||||||
// Byte 获取文件字节
|
// Byte 获取文件字节
|
||||||
@@ -142,33 +171,51 @@ func (this *FileStruct) Byte(path ...any) (result *FileResponse) {
|
|||||||
}
|
}
|
||||||
}(file)
|
}(file)
|
||||||
|
|
||||||
// // 获取文件大小
|
// 获取文件信息
|
||||||
// info, _ := file.Stat()
|
info, err := file.Stat()
|
||||||
// size := info.Size()
|
|
||||||
// // 读取文件
|
|
||||||
// data := make([]byte, size)
|
|
||||||
// file.Read(data)
|
|
||||||
// return data
|
|
||||||
|
|
||||||
var bytes []byte
|
|
||||||
|
|
||||||
// 分批次读取
|
|
||||||
buf := make([]byte, 1024)
|
|
||||||
for {
|
|
||||||
line, err := file.Read(buf)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
this.response.Error = err
|
||||||
|
return this.response
|
||||||
|
}
|
||||||
|
size := info.Size()
|
||||||
|
|
||||||
|
// 小于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
|
break
|
||||||
}
|
}
|
||||||
bytes = append(bytes, buf[:line]...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.response.Byte = bytes
|
this.response.Byte = bytes
|
||||||
this.response.Result = string(bytes)
|
this.response.Text = string(bytes)
|
||||||
|
this.response.Result = bytes
|
||||||
|
|
||||||
return this.response
|
return this.response
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileList 获取指定目录下的所有文件
|
// List 获取指定目录下的所有文件
|
||||||
func (this *FileStruct) List(opt ...map[string]any) (result *FileResponse) {
|
func (this *FileStruct) List(opt ...map[string]any) (result *FileResponse) {
|
||||||
|
|
||||||
// 默认参数
|
// 默认参数
|
||||||
@@ -245,3 +292,119 @@ func (this *FileStruct) List(opt ...map[string]any) (result *FileResponse) {
|
|||||||
this.response.Slice = cast.ToSlice(slice)
|
this.response.Slice = cast.ToSlice(slice)
|
||||||
return this.response
|
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
|
||||||
|
}
|
@@ -41,14 +41,14 @@ func (this *LangModel) Value(key any, args ...any) (result any) {
|
|||||||
text := cast.ToString(key)
|
text := cast.ToString(key)
|
||||||
|
|
||||||
// 解析语言包
|
// 解析语言包
|
||||||
lang := cast.ToStringMap(JsonDecode(bytes.Result))
|
lang := cast.ToStringMap(JsonDecode(bytes.Text))
|
||||||
|
|
||||||
// 获取语言
|
// 获取语言
|
||||||
result = lang[text]
|
result = lang[text]
|
||||||
|
|
||||||
// 如果没有找到语言,通过javascript风格获取
|
// 如果没有找到语言,通过javascript风格获取
|
||||||
if IsEmpty(result) {
|
if IsEmpty(result) {
|
||||||
item, err := JsonGet(bytes.Result, text)
|
item, err := JsonGet(bytes.Text, text)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
result = item
|
result = item
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user