chore: 并入 iotlcm-admin-svr 历史到 admin-svr/(原提交 49818c6)

This commit is contained in:
MiFaZhan
2026-11-02 13:27:59 +08:00
1250 changed files with 154111 additions and 0 deletions
@@ -0,0 +1,78 @@
package excel
import (
"context"
"encoding/csv"
"io"
"os"
"github.com/gogf/gf/v2/errors/gerror"
)
func StreamCSVFile(ctx context.Context, filePath string, options ParseOptions, handler func(ParsedRow) error) (int, error) {
file, err := os.Open(filePath)
if err != nil {
return 0, gerror.Wrap(err, "open CSV file failed")
}
defer file.Close()
return StreamCSVReader(ctx, file, options, handler)
}
func StreamCSVReader(ctx context.Context, reader io.Reader, options ParseOptions, handler func(ParsedRow) error) (int, error) {
if handler == nil {
return 0, gerror.New("CSV row handler cannot be nil")
}
csvReader := csv.NewReader(reader)
csvReader.FieldsPerRecord = -1
csvReader.ReuseRecord = true
headers, err := csvReader.Read()
if err != nil {
if err == io.EOF {
return 0, gerror.New("CSV file has no header")
}
return 0, gerror.Wrap(err, "read CSV header failed")
}
columnIndex, err := buildColumnIndex(headers)
if err != nil {
return 0, err
}
for _, requiredHeader := range options.RequiredHeaders {
if _, ok := columnIndex[normalizeHeader(requiredHeader)]; !ok {
return 0, gerror.Newf("CSV file is missing required column: %s", requiredHeader)
}
}
rowNo := 1
parsedCount := 0
for {
if err = ctx.Err(); err != nil {
return parsedCount, err
}
values, readErr := csvReader.Read()
if readErr == io.EOF {
break
}
if readErr != nil {
return parsedCount, gerror.Wrapf(readErr, "read CSV row %d failed", rowNo+1)
}
rowNo++
if isEmptyRow(values) {
continue
}
fields := make(map[string]string, len(columnIndex))
for columnName, index := range columnIndex {
fields[columnName] = cellValue(values, index)
}
if err = handler(ParsedRow{RowNo: rowNo, Fields: fields}); err != nil {
return parsedCount, err
}
parsedCount++
}
if parsedCount == 0 {
return 0, gerror.New("CSV file has no data rows")
}
return parsedCount, nil
}