diff --git a/main.go b/main.go index 7905807..ade6b0b 100644 --- a/main.go +++ b/main.go @@ -2,4 +2,45 @@ package 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) + // } +} \ No newline at end of file diff --git a/text.log b/text.log new file mode 100644 index 0000000..fe7b406 --- /dev/null +++ b/text.log @@ -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行 内容 \ No newline at end of file diff --git a/utils/file.go b/utils/file.go index fb17acb..5f1a822 100644 --- a/utils/file.go +++ b/utils/file.go @@ -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 } \ No newline at end of file diff --git a/utils/lang.go b/utils/lang.go index 1aaf93f..9a3f044 100644 --- a/utils/lang.go +++ b/utils/lang.go @@ -41,14 +41,14 @@ func (this *LangModel) Value(key any, args ...any) (result any) { text := cast.ToString(key) // 解析语言包 - lang := cast.ToStringMap(JsonDecode(bytes.Result)) + lang := cast.ToStringMap(JsonDecode(bytes.Text)) // 获取语言 result = lang[text] // 如果没有找到语言,通过javascript风格获取 if IsEmpty(result) { - item, err := JsonGet(bytes.Result, text) + item, err := JsonGet(bytes.Text, text) if err == nil { result = item }