1075 lines
29 KiB
Go
1075 lines
29 KiB
Go
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"sync"
|
||
)
|
||
|
||
//
|
||
//var (
|
||
// headerOnce sync.Once
|
||
// fileHandle int64 = -1
|
||
//)
|
||
//
|
||
//// testwrite 函数 - 使用sync.Once确保表头只写入一次
|
||
//func testwrite(mgr *CSVManager, batchIndex int, wg *sync.WaitGroup) {
|
||
// defer wg.Done()
|
||
//
|
||
// fmt.Printf("协程 %d 开始执行...\n", batchIndex)
|
||
//
|
||
// // 1. 打开CSV文件 - 所有协程操作同一个文件
|
||
// filename := "csv/test_concurrent.csv"
|
||
// delimiter := ','
|
||
// hasHeader := true
|
||
//
|
||
// handleID, err := mgr.OpenCSVFile(filename, delimiter, hasHeader)
|
||
// if err != nil {
|
||
// fmt.Printf("协程 %d 打开文件失败: %v\n", batchIndex, err)
|
||
// return
|
||
// }
|
||
//
|
||
// fmt.Printf("协程 %d 成功打开文件,句柄ID: %d\n", batchIndex, handleID)
|
||
//
|
||
// // 2. 使用sync.Once确保表头只写入一次
|
||
// headerOnce.Do(func() {
|
||
// header := []string{
|
||
// "ID", "Name",
|
||
// }
|
||
//
|
||
// err = mgr.WriteHeader(handleID, header)
|
||
// if err != nil {
|
||
// fmt.Printf("写入表头失败: %v\n", err)
|
||
// } else {
|
||
// fmt.Println("表头写入成功(仅第一次)")
|
||
// }
|
||
// })
|
||
//
|
||
// // 3. 生成并写入1000条数据
|
||
// batchSize := 1000
|
||
// //testData := generateTestData(batchIndex, batchSize)
|
||
//
|
||
// var rows [][]string
|
||
//
|
||
// for i := 0; i < batchSize; i++ {
|
||
// //rowIndex := batchIndex*batchSize + i + 1
|
||
// row := []string{
|
||
// fmt.Sprintf("%d", i),
|
||
// fmt.Sprintf("用户_%d", i),
|
||
// }
|
||
// rows = append(rows, row)
|
||
// // 批量写入数据
|
||
// _, err = mgr.AppendRows(handleID, rows)
|
||
// if err != nil {
|
||
// fmt.Printf("协程 %d 写入数据失败: %v\n", batchIndex, err)
|
||
// mgr.CloseHandle(handleID)
|
||
// return
|
||
// }
|
||
//
|
||
// fmt.Printf("协程 %d 成功写入 %d 条数据\n", batchIndex, i)
|
||
// rows = nil
|
||
// }
|
||
//
|
||
// //return rows
|
||
//
|
||
// // 4. 关闭句柄
|
||
// err = mgr.CloseHandle(handleID)
|
||
// if err != nil {
|
||
// fmt.Printf("协程 %d 关闭句柄失败: %v\n", batchIndex, err)
|
||
// } else {
|
||
// fmt.Printf("协程 %d 关闭句柄成功: %d\n", batchIndex, handleID)
|
||
// }
|
||
//
|
||
// fmt.Printf("协程 %d 执行完成\n", batchIndex)
|
||
//}
|
||
//
|
||
//// 生成测试数据
|
||
//func generateTestData(batchIndex, batchSize int) [][]string {
|
||
// var rows [][]string
|
||
//
|
||
// for i := 0; i < batchSize; i++ {
|
||
// rowIndex := batchIndex*batchSize + i + 1
|
||
// row := []string{
|
||
// fmt.Sprintf("%d", rowIndex),
|
||
// fmt.Sprintf("用户_%d", rowIndex),
|
||
// fmt.Sprintf("user%d@example.com", rowIndex),
|
||
// fmt.Sprintf("%d", 20+(rowIndex%50)),
|
||
// fmt.Sprintf("地址_%d", rowIndex),
|
||
// fmt.Sprintf("13800138%03d", rowIndex%1000),
|
||
// []string{"active", "inactive", "pending"}[rowIndex%3],
|
||
// fmt.Sprintf("%d", 50+(rowIndex%50)),
|
||
// []string{"A", "B", "C", "D"}[rowIndex%4],
|
||
// fmt.Sprintf("tag%d,tag%d", rowIndex, rowIndex+1),
|
||
// }
|
||
// rows = append(rows, row)
|
||
// }
|
||
//
|
||
// return rows
|
||
//}
|
||
//
|
||
//func main() {
|
||
// fmt.Println("开始多协程CSV写入测试...")
|
||
// fmt.Println("所有协程同时操作同一个文件:test_concurrent.csv")
|
||
// fmt.Println("每个协程执行:打开文件 → 写入表头(仅第一次)→ 写入1000条数据 → 关闭文件")
|
||
// fmt.Println("启动10个协程,总共写入10000条数据")
|
||
//
|
||
// // 获取CSV管理器
|
||
// mgr := GetManager()
|
||
//
|
||
// // 创建等待组
|
||
// var wg sync.WaitGroup
|
||
//
|
||
// // 启动10个协程,每个协程执行完整的操作流程
|
||
// totalGoroutines := 4
|
||
//
|
||
// for i := 0; i < totalGoroutines; i++ {
|
||
// wg.Add(1)
|
||
// go testwrite(mgr, i, &wg)
|
||
// }
|
||
//
|
||
// // 等待所有协程完成
|
||
// wg.Wait()
|
||
//
|
||
// fmt.Println("\n所有协程执行完成!")
|
||
// fmt.Println("测试文件:test_concurrent.csv")
|
||
//}
|
||
|
||
//import "C"
|
||
//import (
|
||
// "bytes"
|
||
// "encoding/csv"
|
||
// "encoding/json"
|
||
// "fmt"
|
||
// "io"
|
||
// "net/http"
|
||
// "os"
|
||
// "path/filepath"
|
||
// "syscall"
|
||
// "unsafe"
|
||
//)
|
||
//
|
||
//// CsvDLL 代理DLL结构
|
||
//type csvDLL struct {
|
||
// dll *syscall.DLL
|
||
// openCSVFile *syscall.Proc // 打开/创建CSV文件
|
||
// readRows *syscall.Proc // 读取多行数据
|
||
// writeRows *syscall.Proc // 写入/覆盖行数据
|
||
// appendRows *syscall.Proc // 追加行数据
|
||
// getRowCount *syscall.Proc // 获取总行数
|
||
// findRows *syscall.Proc // 搜索行
|
||
// closeCSVFile *syscall.Proc // 关闭CSV文件
|
||
// mergeCSVFiles *syscall.Proc // 合并多个CSV文件
|
||
// getError *syscall.Proc // 获取错误信息
|
||
// updateCSVRowSafe *syscall.Proc
|
||
// createOpenCSVFile *syscall.Proc
|
||
// freeCString *syscall.Proc // 释放C字符串
|
||
//}
|
||
//
|
||
//// 初始化csvDLL
|
||
//func InitCsvDLL() (*csvDLL, error) {
|
||
// dllPath := filepath.Join("csv/dll", "csv.dll")
|
||
// if _, err := os.Stat(dllPath); os.IsNotExist(err) {
|
||
// return nil, fmt.Errorf("csv DLL 不存在: %s", dllPath)
|
||
// }
|
||
// if dll, err := syscall.LoadDLL(dllPath); err != nil {
|
||
// return nil, fmt.Errorf("加载csv DLL 失败: %s", err)
|
||
// } else {
|
||
// return &csvDLL{
|
||
// dll: dll,
|
||
// openCSVFile: dll.MustFindProc("OpenCSVFile"),
|
||
// updateCSVRowSafe: dll.MustFindProc("UpdateCSVRowSafe"),
|
||
// readRows: dll.MustFindProc("ReadRows"),
|
||
// writeRows: dll.MustFindProc("WriteRows"),
|
||
// appendRows: dll.MustFindProc("AppendRows"),
|
||
// getRowCount: dll.MustFindProc("GetRowCount"),
|
||
// findRows: dll.MustFindProc("FindRows"),
|
||
// closeCSVFile: dll.MustFindProc("CloseCSVFile"),
|
||
// mergeCSVFiles: dll.MustFindProc("MergeCSVFiles"),
|
||
// createOpenCSVFile: dll.MustFindProc("CreateOpenCSVFile"),
|
||
// getError: dll.MustFindProc("GetError"),
|
||
// freeCString: dll.MustFindProc("FreeCString"),
|
||
// }, nil
|
||
// }
|
||
//}
|
||
//
|
||
//// cStr 获取C字符串
|
||
//func (m *csvDLL) cStr(p uintptr) string {
|
||
// if p == 0 {
|
||
// return ""
|
||
// }
|
||
// b := []byte{}
|
||
// for i := uintptr(0); ; i++ {
|
||
// c := *(*byte)(unsafe.Pointer(p + i))
|
||
// if c == 0 {
|
||
// break
|
||
// }
|
||
// b = append(b, c)
|
||
// }
|
||
// s := string(b)
|
||
// if m.freeCString != nil {
|
||
// m.freeCString.Call(p)
|
||
// }
|
||
// return s
|
||
//}
|
||
//
|
||
//// 打开/创建CSV文件
|
||
//func (m *csvDLL) OpenCSVFile(filePath string, delimiter byte, hasHeader bool) (int64, error) {
|
||
// proc, err := m.dll.FindProc("OpenCSVFile")
|
||
// if err != nil {
|
||
// return -1, fmt.Errorf("找不到函数 OpenCSVFile: %v", err)
|
||
// }
|
||
// filePathPtr, _ := syscall.BytePtrFromString(filePath)
|
||
// hasHeaderInt := 0
|
||
// if hasHeader {
|
||
// hasHeaderInt = 1
|
||
// }
|
||
// info, _, _ := proc.Call(
|
||
// uintptr(unsafe.Pointer(filePathPtr)),
|
||
// uintptr(delimiter),
|
||
// uintptr(hasHeaderInt))
|
||
//
|
||
// return int64(info), nil
|
||
//}
|
||
//
|
||
//// CSV响应结构体
|
||
//type CSVResponses struct {
|
||
// Success bool `json:"success"`
|
||
// Message string `json:"message,omitempty"`
|
||
// Data CSVData `json:"data,omitempty"`
|
||
//}
|
||
//
|
||
//type CSVData struct {
|
||
// HandleID int64 `json:"handleID"`
|
||
//}
|
||
//
|
||
//func (m *csvDLL) CreateOpenCSVFile(filePath string, delimiter byte, hasHeader bool) (*CSVResponses, error) {
|
||
// proc, err := m.dll.FindProc("CreateOpenCSVFile")
|
||
// if err != nil {
|
||
// return nil, fmt.Errorf("找不到函数 CreateOpenCSVFile: %v", err)
|
||
// }
|
||
// filePathPtr, _ := syscall.BytePtrFromString(filePath)
|
||
// hasHeaderInt := 0
|
||
// if hasHeader {
|
||
// hasHeaderInt = 1
|
||
// }
|
||
// info, _, _ := proc.Call(
|
||
// uintptr(unsafe.Pointer(filePathPtr)),
|
||
// uintptr(delimiter),
|
||
// uintptr(hasHeaderInt))
|
||
// var csvResponse CSVResponses
|
||
// str := m.cStr(info)
|
||
// if err := json.Unmarshal([]byte(str), &csvResponse); err != nil {
|
||
// return nil, err
|
||
// }
|
||
// return &csvResponse, nil
|
||
//}
|
||
//
|
||
//func (m *csvDLL) UpdateCSVRowSafe(handleID int64, rowNum int, newRow []string) (*CSVResponses, error) {
|
||
// proc, err := m.dll.FindProc("UpdateCSVRowSafe")
|
||
// if err != nil {
|
||
// return nil, fmt.Errorf("找不到函数 UpdateCSVRowSafe: %v", err)
|
||
// }
|
||
// jsonString, _ := json.Marshal(newRow)
|
||
// newRowPtr, _ := syscall.BytePtrFromString(string(jsonString))
|
||
// info, _, _ := proc.Call(
|
||
// uintptr(handleID),
|
||
// uintptr(rowNum),
|
||
// uintptr(unsafe.Pointer(newRowPtr)))
|
||
// var csvResponse CSVResponses
|
||
// str := m.cStr(info)
|
||
// if err := json.Unmarshal([]byte(str), &csvResponse); err != nil {
|
||
// return nil, err
|
||
// }
|
||
// return &csvResponse, nil
|
||
//}
|
||
//
|
||
////// 读取多行数据
|
||
////func (m *csvDLL) ReadRows(handle int64) ([]string, error) {
|
||
//// proc, err := m.dll.FindProc("ReadRows")
|
||
//// if err != nil {
|
||
//// return nil, fmt.Errorf("找不到函数 ReadRows: %v", err)
|
||
//// }
|
||
////
|
||
////}
|
||
//
|
||
//// 写入/覆盖行数据
|
||
//func (m *csvDLL) WriteRows(handle int64, rowsData [][]string, header int) (int, error) {
|
||
// proc, err := m.dll.FindProc("WriteRows")
|
||
// if err != nil {
|
||
// return -1, fmt.Errorf("找不到函数 WriteRows: %v", err)
|
||
// }
|
||
// var buffer bytes.Buffer
|
||
// writer := csv.NewWriter(&buffer)
|
||
// // 写入所有行
|
||
// if err := writer.WriteAll(rowsData); err != nil {
|
||
// return -1, fmt.Errorf("序列化 CSV 数据失败: %v", err)
|
||
// }
|
||
// writer.Flush()
|
||
//
|
||
// // 转换为 C 字符串
|
||
// cStr := C.CString(buffer.String())
|
||
//
|
||
// ret, _, _ := proc.Call(
|
||
// uintptr(handle),
|
||
// uintptr(unsafe.Pointer(cStr)),
|
||
// uintptr(header))
|
||
//
|
||
// freeProc, _ := m.dll.FindProc("FreeCString")
|
||
// if freeProc != nil {
|
||
// defer freeProc.Call(uintptr(unsafe.Pointer(cStr)))
|
||
// }
|
||
// return int(ret), nil
|
||
//}
|
||
//
|
||
//// 定义请求结构体
|
||
//type OpenCSVRequest struct {
|
||
// FilePath string `json:"filePath"`
|
||
// Delimiter string `json:"delimiter"` // 可以是逗号、分号等字符
|
||
// HasHeader bool `json:"hasHeader"`
|
||
//}
|
||
//
|
||
//// 定义响应结构体
|
||
//type OpenCSVResponse struct {
|
||
// Success bool `json:"success"`
|
||
// Message string `json:"message"`
|
||
// Handle int64 `json:"handle,omitempty"`
|
||
// Error string `json:"error,omitempty"`
|
||
//}
|
||
//
|
||
//func handleOpenCSVFile(w http.ResponseWriter, r *http.Request) {
|
||
// // 设置响应头
|
||
// w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||
//
|
||
// // 只允许 POST 请求
|
||
// if r.Method != http.MethodPost {
|
||
// response := OpenCSVResponse{
|
||
// Success: false,
|
||
// Message: "只支持POST请求",
|
||
// }
|
||
// w.WriteHeader(http.StatusMethodNotAllowed)
|
||
// json.NewEncoder(w).Encode(response)
|
||
// return
|
||
// }
|
||
//
|
||
// // 1.初始化DLL管理器
|
||
// dll, err := InitCsvDLL()
|
||
// if err != nil {
|
||
// response := OpenCSVResponse{
|
||
// Success: false,
|
||
// Message: "初始化DLL失败",
|
||
// Error: err.Error(),
|
||
// }
|
||
// w.WriteHeader(http.StatusInternalServerError)
|
||
// json.NewEncoder(w).Encode(response)
|
||
// return
|
||
// }
|
||
//
|
||
// // 2.读取请求体
|
||
// body, err := io.ReadAll(r.Body)
|
||
// if err != nil {
|
||
// response := OpenCSVResponse{
|
||
// Success: false,
|
||
// Message: "读取请求体失败",
|
||
// Error: err.Error(),
|
||
// }
|
||
// w.WriteHeader(http.StatusInternalServerError)
|
||
// json.NewEncoder(w).Encode(response)
|
||
// return
|
||
// }
|
||
// defer r.Body.Close()
|
||
//
|
||
// // 3.解析JSON请求
|
||
// var req OpenCSVRequest
|
||
// if err := json.Unmarshal(body, &req); err != nil {
|
||
// response := OpenCSVResponse{
|
||
// Success: false,
|
||
// Message: "JSON解析失败",
|
||
// Error: err.Error(),
|
||
// }
|
||
// w.WriteHeader(http.StatusInternalServerError)
|
||
// json.NewEncoder(w).Encode(response)
|
||
// return
|
||
// }
|
||
//
|
||
// // 4.验证必填参数
|
||
// if req.FilePath == "" {
|
||
// response := OpenCSVResponse{
|
||
// Success: false,
|
||
// Message: "filePath参数不能为空",
|
||
// }
|
||
// w.WriteHeader(http.StatusBadRequest)
|
||
// json.NewEncoder(w).Encode(response)
|
||
// return
|
||
// }
|
||
//
|
||
// // 5. 处理分隔符参数
|
||
// delimiter := ','
|
||
// if req.Delimiter != "" {
|
||
// // 确保分隔符是单个字符
|
||
// if len(req.Delimiter) == 1 {
|
||
// delimiter = rune(req.Delimiter[0])
|
||
// } else {
|
||
// // 尝试解析常见分隔符的字符串表示
|
||
// switch req.Delimiter {
|
||
// case "comma", ",":
|
||
// delimiter = ','
|
||
// case "semicolon", ";":
|
||
// delimiter = ';'
|
||
// case "tab", "\t":
|
||
// delimiter = '\t'
|
||
// case "pipe", "|":
|
||
// delimiter = '|'
|
||
// default:
|
||
// response := OpenCSVResponse{
|
||
// Success: false,
|
||
// Message: "无效的分隔符,请使用单个字符或预定义的分隔符名称",
|
||
// }
|
||
// w.WriteHeader(http.StatusBadRequest)
|
||
// json.NewEncoder(w).Encode(response)
|
||
// return
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// // 6. 调用DLL函数
|
||
// handle, err := dll.OpenCSVFile(req.FilePath, byte(delimiter), req.HasHeader)
|
||
// if err != nil {
|
||
// response := OpenCSVResponse{
|
||
// Success: false,
|
||
// Message: "打开CSV文件失败",
|
||
// Error: err.Error(),
|
||
// }
|
||
// w.WriteHeader(http.StatusInternalServerError)
|
||
// json.NewEncoder(w).Encode(response)
|
||
// return
|
||
// }
|
||
//
|
||
// // 7. 返回成功响应
|
||
// response := OpenCSVResponse{
|
||
// Success: true,
|
||
// Message: "CSV文件打开成功",
|
||
// Handle: handle,
|
||
// }
|
||
// w.WriteHeader(http.StatusOK)
|
||
// json.NewEncoder(w).Encode(response)
|
||
//}
|
||
//
|
||
//// 解码从DLL读取的数据
|
||
//func decodeRowData(buffer []byte, maxBytes int) [][]string {
|
||
// var rows [][]string
|
||
// var currentRow []string
|
||
//
|
||
// offset := 0
|
||
// for offset < maxBytes {
|
||
// if offset+4 > maxBytes {
|
||
// break
|
||
// }
|
||
//
|
||
// // 读取单元格长度
|
||
// cellLen := int(uint32(buffer[offset]) |
|
||
// uint32(buffer[offset+1])<<8 |
|
||
// uint32(buffer[offset+2])<<16 |
|
||
// uint32(buffer[offset+3])<<24)
|
||
// offset += 4
|
||
//
|
||
// if cellLen == 0 {
|
||
// // 行结束
|
||
// if len(currentRow) > 0 {
|
||
// rows = append(rows, currentRow)
|
||
// currentRow = nil
|
||
// }
|
||
// continue
|
||
// }
|
||
//
|
||
// if offset+cellLen > maxBytes {
|
||
// break
|
||
// }
|
||
//
|
||
// // 读取单元格数据
|
||
// cell := string(buffer[offset : offset+cellLen])
|
||
// offset += cellLen
|
||
// currentRow = append(currentRow, cell)
|
||
// }
|
||
//
|
||
// return rows
|
||
//}
|
||
|
||
//func main() {
|
||
// 使用dll文件
|
||
//dll, err := InitCsvDLL()
|
||
//if err != nil {
|
||
//
|
||
//}
|
||
//file, err := dll.CreateOpenCSVFile("csv/taskLog.csv", ',', true)
|
||
//if err != nil {
|
||
//
|
||
//}
|
||
//newRow := []string{"9787115524539", "100.00", "1", "上传成功", ""}
|
||
//safe, err := dll.UpdateCSVRowSafe(file.Data.HandleID, 9, newRow)
|
||
//if err != nil {
|
||
//
|
||
//}
|
||
//marshal, _ := json.Marshal(safe)
|
||
//fmt.Println(string(marshal))
|
||
|
||
//file, err := GetManager().OpenCSVFile("csv/taskLog1.csv", ',', true)
|
||
//if err != nil {
|
||
// fmt.Println(err)
|
||
//}
|
||
//fmt.Println(file)
|
||
|
||
//handle, err := GetManager().getHandle(2)
|
||
//if err != nil {
|
||
// fmt.Println(err)
|
||
//}
|
||
// 获取指定数量的行
|
||
//row, err := handle.readRows(100)
|
||
//if err != nil {
|
||
// fmt.Println(err)
|
||
//}
|
||
//for _, i := range row {
|
||
// fmt.Println(i)
|
||
//}
|
||
|
||
//// 获取总行数
|
||
//row, err := handle.getTotalRows()
|
||
//if err != nil {
|
||
// fmt.Println(err)
|
||
//}
|
||
//fmt.Println(row)
|
||
//newRow := []string{
|
||
// "9787107267505", "20.00", "10", "上传成功", "877133619369",
|
||
//}
|
||
//
|
||
//row, err := GetManager().modifyRow(file, 1, newRow)
|
||
//if err != nil {
|
||
// fmt.Println(err)
|
||
//}
|
||
//fmt.Println(row)
|
||
|
||
//http.HandleFunc("/csv/openCSVFile", handleOpenCSVFile)
|
||
//port := "8080"
|
||
//server := &http.Server{
|
||
// Addr: ":" + port,
|
||
// Handler: nil,
|
||
//}
|
||
//
|
||
//// 4. 优雅关闭设置
|
||
//done := make(chan bool, 1)
|
||
//quit := make(chan os.Signal, 1)
|
||
//signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||
//
|
||
//// 5. 优雅关闭协程
|
||
//go func() {
|
||
// <-quit
|
||
// fmt.Println("\n服务器正在关闭...")
|
||
//
|
||
// ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||
// defer cancel()
|
||
//
|
||
// if err := server.Shutdown(ctx); err != nil {
|
||
// fmt.Printf("强制关闭服务器: %v\n", err)
|
||
// }
|
||
// close(done)
|
||
//}()
|
||
//
|
||
//// 启动服务器
|
||
//if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||
// fmt.Printf("服务器启动失败: %s\n", err)
|
||
//}
|
||
//// 7. 等待关闭完成
|
||
//<-done
|
||
//fmt.Println("服务器已关闭")
|
||
//}
|
||
|
||
// 主函数 - 测试代码
|
||
//func main() {
|
||
// fmt.Println("=== CSV句柄管理器测试 ===") //7984
|
||
//
|
||
// filename := "csv/2006557053525397505_2013842964755726337_20260121_1.csv"
|
||
// ////dstFile := "csv/taskLog3.csv"
|
||
// //fmt.Printf("1. 创建测试文件: %s\n", filename)
|
||
// //
|
||
// // 创建 Redis 客户端
|
||
// //rdb := redis.NewClient(&redis.Options{
|
||
// // Addr: "192.168.101.209:6379", // Redis 地址
|
||
// // Password: "", // 密码,没有则为空
|
||
// // DB: 0, // 使用的数据库编号
|
||
// //})
|
||
// //
|
||
// //// 创建上下文
|
||
// //ctx := context.Background()
|
||
// //
|
||
// //// 测试连接
|
||
// //pong, err := rdb.Ping(ctx).Result()
|
||
// //if err != nil {
|
||
// // log.Fatal("连接 Redis 失败:", err)
|
||
// //}
|
||
// //fmt.Println("连接成功:", pong)
|
||
//
|
||
// //key := "2006557053525397505_2010589232836288513_20260112_1"
|
||
//
|
||
// //// 获取值
|
||
// //val, err := rdb.Get(ctx, "1995373681100910593_2010521216979214337_20260112_1").Result()
|
||
// //if err != nil {
|
||
// // log.Fatal("获取键值失败:", err)
|
||
// //}
|
||
// //fmt.Println("key:", val)
|
||
//
|
||
// handleID, err := GetManager().OpenCSVFile(filename, ',', true)
|
||
// if err != nil {
|
||
// fmt.Printf("打开文件失败: %v\n", err)
|
||
// }
|
||
//
|
||
// fmt.Printf("2. 打开文件成功,句柄ID: %d\n", handleID)
|
||
//
|
||
// //// 测试写入表头
|
||
// //header := []string{"ID", "data"}
|
||
// //err = GetManager().WriteHeader(handleID, header)
|
||
// //if err != nil {
|
||
// // fmt.Printf("写入表头失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Println("写入表头成功")
|
||
// //}
|
||
//
|
||
// //// 获取列表所有元素
|
||
// //listValues, err := rdb.LRange(ctx, key, 0, -1).Result()
|
||
// //if err != nil {
|
||
// // log.Fatal("获取列表失败:", err)
|
||
// //}
|
||
// //
|
||
// //fmt.Printf("列表包含 %d 个元素:\n", len(listValues))
|
||
// //for i, value := range listValues {
|
||
// //
|
||
// // fmt.Printf(" [%d] %s\n", i, value)
|
||
// //
|
||
// // rowsData := [][]string{
|
||
// // {fmt.Sprintf("%d", i), value},
|
||
// // }
|
||
// //
|
||
// // totalRows, err := GetManager().WriteRows(handleID, rowsData)
|
||
// // if err != nil {
|
||
// // fmt.Printf("批量写入数据失败: %v\n", err)
|
||
// // } else {
|
||
// // fmt.Printf("批量写入数据成功,行数: %d\n", totalRows)
|
||
// // }
|
||
// //
|
||
// //}
|
||
// //
|
||
// //// 3. 也可以检查键是否存在
|
||
// //exists, err := rdb.Exists(ctx, key).Result()
|
||
// //if err != nil {
|
||
// // log.Fatal("检查键是否存在失败:", err)
|
||
// //}
|
||
// //if exists == 0 {
|
||
// // fmt.Printf("键 '%s' 不存在\n", key)
|
||
// //} else {
|
||
// // fmt.Printf("键 '%s' 存在\n", key)
|
||
// //}
|
||
// //
|
||
// //// 关闭连接
|
||
// //defer rdb.Close()
|
||
//
|
||
// //
|
||
// //// 2. 创建目标文件(部分数据)
|
||
// //dstHandle, err := GetManager().OpenCSVFile(dstFile, ',', true)
|
||
// //if err != nil {
|
||
// // fmt.Printf("创建目标文件失败: %v", err)
|
||
// //}
|
||
// //// 合并
|
||
// //totalRows, err := GetManager().MergeCSVFilesSimple(handleID, dstHandle, true)
|
||
// //if err != nil {
|
||
// // fmt.Printf("合并文件失败: %v", err)
|
||
// //}
|
||
// //fmt.Println(totalRows)
|
||
//
|
||
// //for i := 0; i < 10000; i++ {
|
||
// // // 打开CSV文件
|
||
// // handleID, err := GetManager().OpenCSVFile(filename, ',', true)
|
||
// // if err != nil {
|
||
// // fmt.Printf("打开文件失败: %v\n", err)
|
||
// // }
|
||
// //
|
||
// // fmt.Printf("2. 打开文件成功,句柄ID: %d\n", handleID)
|
||
// //
|
||
// // // 测试写入表头
|
||
// // header := []string{"ID", "Name", "Age", "Email"}
|
||
// // err = GetManager().WriteHeader(handleID, header)
|
||
// // if err != nil {
|
||
// // fmt.Printf("写入表头失败: %v\n", err)
|
||
// // } else {
|
||
// // fmt.Println("写入表头成功")
|
||
// // }
|
||
// //
|
||
// // //// 写入测试数据
|
||
// // //rowsData := [][]string{
|
||
// // // {"1", fmt.Sprintf("张三", i), "25", "zhangsan@example.com"},
|
||
// // // {"2", "李四", "30", "lisi@example.com"},
|
||
// // // {"3", "王五", "28", "wangwu@example.com"},
|
||
// // // {"4", "赵六", "35", "zhaoliu@example.com"},
|
||
// // //}
|
||
// //
|
||
// // // 写入测试数据
|
||
// // rowsData := [][]string{
|
||
// // {fmt.Sprintf("%d", i+100), "张三", fmt.Sprintf("%d", i+1000), fmt.Sprintf("%d", i+10000)},
|
||
// // }
|
||
// //
|
||
// // totalRows, err := GetManager().WriteRows(handleID, rowsData)
|
||
// // if err != nil {
|
||
// // fmt.Printf("批量写入数据失败: %v\n", err)
|
||
// // } else {
|
||
// // fmt.Printf("批量写入数据成功,行数: %d\n", totalRows)
|
||
// // }
|
||
// //
|
||
// // GetManager().CloseHandle(handleID)
|
||
// //}
|
||
//
|
||
// //// 测试写入表头
|
||
// //header := []string{"ID", "Name", "Age", "Email"}
|
||
// //err = GetManager().WriteHeader(handleID, header)
|
||
// //if err != nil {
|
||
// // fmt.Printf("写入表头失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Println("写入表头成功")
|
||
// //}
|
||
//
|
||
// //// 写入测试数据
|
||
// //rowsData := [][]string{
|
||
// // {"1", "张三", "25", "zhangsan@example.com"},
|
||
// // {"2", "李四", "30", "lisi@example.com"},
|
||
// // {"3", "王五", "28", "wangwu@example.com"},
|
||
// // {"4", "赵六", "35", "zhaoliu@example.com"},
|
||
// //}
|
||
// //
|
||
// //totalRows, err := GetManager().WriteRows(handleID, rowsData)
|
||
// //if err != nil {
|
||
// // fmt.Printf("批量写入数据失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Printf("批量写入数据成功,行数: %d\n", totalRows)
|
||
// //}
|
||
// //
|
||
// //// 获取写入后的总行数
|
||
// //totalRows, err = GetManager().GetTotalRows(handleID)
|
||
// //if err != nil {
|
||
// // fmt.Printf("获取总行数失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Printf("写入后总行数: %d\n", totalRows)
|
||
// //}
|
||
//
|
||
// //// ============ 测试修改行功能 ============
|
||
// //
|
||
// //fmt.Println("\n3. 测试修改行功能")
|
||
// //
|
||
// //// 修改第1行数据(索引0)
|
||
// //newRow1 := []string{"1", "张三(已修改1)", "26", "zhangsan_updated@example.com"}
|
||
// //err = GetManager().UpdateRow(handleID, 0, newRow1)
|
||
// //if err != nil {
|
||
// // fmt.Printf("修改第1行数据失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Println("修改第1行数据成功")
|
||
// //}
|
||
// //
|
||
// //// 修改第3行数据(索引2)
|
||
// //newRow3 := []string{"3", "王五(已修改)", "29", "wangwu_updated@example.com"}
|
||
// //err = GetManager().UpdateRow(handleID, 2, newRow3)
|
||
// //if err != nil {
|
||
// // fmt.Printf("修改第3行数据失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Println("修改第3行数据成功")
|
||
// //}
|
||
// //
|
||
// //// 获取修改后的行数据
|
||
// //fmt.Println("\n4. 获取修改后的行数据")
|
||
//
|
||
// for i := 0; i < 10000; i++ {
|
||
// row1, err := GetManager().GetRow(handleID, int64(i))
|
||
// if err != nil {
|
||
// fmt.Printf("获取第 %d 行失败: %v\n", i, err)
|
||
// } else {
|
||
// fmt.Printf("第 %d 行数据: %v\n", i, row1)
|
||
// }
|
||
// }
|
||
// //获取第1行
|
||
// //row1, err := GetManager().GetRow(handleID, 10)
|
||
// //if err != nil {
|
||
// // fmt.Printf("获取第1行失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Printf("第1行数据: %v\n", row1)
|
||
// //}
|
||
//
|
||
// //// 获取第3行
|
||
// //row3, err := GetManager().GetRow(handleID, 2)
|
||
// //if err != nil {
|
||
// // fmt.Printf("获取第3行失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Printf("第3行数据: %v\n", row3)
|
||
// //}
|
||
//
|
||
// //// ============ 测试批量修改功能 ============
|
||
// //
|
||
// //fmt.Println("\n5. 测试批量修改功能")
|
||
// //
|
||
// //updates := map[int64][]string{
|
||
// // 1: {"2", "李四(批量修改)", "31", "lisi_batch@example.com"},
|
||
// // 3: {"4", "赵六(批量修改)", "36", "zhaoliu_batch@example.com"},
|
||
// //}
|
||
// //
|
||
// //updatedCount, err := GetManager().UpdateRows(handleID, updates)
|
||
// //if err != nil {
|
||
// // fmt.Printf("批量修改失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Printf("批量修改成功,修改了%d行\n", updatedCount)
|
||
// //}
|
||
// //
|
||
// //// 验证批量修改结果
|
||
// //row2, err := GetManager().GetRow(handleID, 1)
|
||
// //if err != nil {
|
||
// // fmt.Printf("获取第2行失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Printf("第2行数据(批量修改后): %v\n", row2)
|
||
// //}
|
||
// //
|
||
// //row4, err := GetManager().GetRow(handleID, 3)
|
||
// //if err != nil {
|
||
// // fmt.Printf("获取第4行失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Printf("第4行数据(批量修改后): %v\n", row4)
|
||
// //}
|
||
// //
|
||
// //// 获取最终总行数
|
||
// //finalTotalRows, err := GetManager().GetTotalRows(handleID)
|
||
// //if err != nil {
|
||
// // fmt.Printf("获取最终总行数失败: %v\n", err)
|
||
// //} else {
|
||
// // fmt.Printf("最终总行数: %d\n", finalTotalRows)
|
||
// //}
|
||
//
|
||
// // 清理
|
||
// GetManager().closeAllHandles()
|
||
// fmt.Println("\n测试完成!")
|
||
//}
|
||
|
||
func main() {
|
||
filename := "csv/taskLog.csv"
|
||
handleID, err := GetManager().OpenCSVFile(filename, ',', true)
|
||
if err != nil {
|
||
fmt.Println(err.Error())
|
||
}
|
||
fmt.Println(handleID)
|
||
headers := []string{"ID", "序号", "姓名", "年龄"}
|
||
err = GetManager().WriteHeader(handleID, headers)
|
||
if err != nil {
|
||
fmt.Println(err.Error())
|
||
}
|
||
|
||
//rowss, i, err := GetManager().AppendRowss(handleID, rows)
|
||
//if err != nil {
|
||
// fmt.Println(err.Error())
|
||
//}
|
||
//fmt.Println(rowss)
|
||
//fmt.Println(i)
|
||
|
||
var wg sync.WaitGroup
|
||
results := make([][]int64, 100)
|
||
|
||
for i := 0; i < 100; i++ {
|
||
rows := [][]string{
|
||
{fmt.Sprintf("%d", i), fmt.Sprintf("%d", i), fmt.Sprintf("张三%d", i), fmt.Sprintf("3%d", i)},
|
||
}
|
||
wg.Add(1)
|
||
go func(idx int) {
|
||
defer wg.Done()
|
||
rowsss, _ := GetManager().AppendRowsNum(handleID, rows)
|
||
fmt.Println(rows, ":", rowsss)
|
||
results[idx] = rowsss
|
||
}(i)
|
||
}
|
||
|
||
wg.Wait()
|
||
|
||
//rowsss, err := GetManager().AppendRowsss(handleID, rows)
|
||
//if err != nil {
|
||
// fmt.Println(err.Error())
|
||
//}
|
||
//fmt.Println(rowsss)
|
||
|
||
GetManager().CloseHandle(handleID)
|
||
|
||
}
|
||
|
||
// WriteRowss 批量写入多行数据到CSV文件
|
||
// 返回写入的起始行号和写入的行数,错误时返回(-1, -1, error)
|
||
func (mgr *CSVManager) WriteRowss(handleID int64, rows [][]string) (int64, int64, error) {
|
||
// 首先记录日志
|
||
if err := mgr.logWriteRows(handleID, rows); err != nil {
|
||
// 日志记录失败不影响主流程,但可以打印警告
|
||
fmt.Printf("警告:记录日志失败: %v\n", err)
|
||
}
|
||
|
||
// 获取句柄
|
||
handle, err := mgr.getHandle(handleID)
|
||
if err != nil {
|
||
return -1, -1, fmt.Errorf("WriteRows 获取句柄失败: %w", err)
|
||
}
|
||
defer mgr.releaseHandle(handleID)
|
||
|
||
// 检查句柄状态
|
||
if !handle.beginOperation() {
|
||
return -1, -1, fmt.Errorf("句柄已关闭或正在关闭: %d", handleID)
|
||
}
|
||
defer handle.endOperation()
|
||
|
||
handle.mu.Lock()
|
||
defer handle.mu.Unlock()
|
||
|
||
if !handle.IsOpen {
|
||
return -1, -1, fmt.Errorf("文件未打开")
|
||
}
|
||
|
||
// 检查是否有表头
|
||
if handle.HasHeader && len(handle.Header) > 0 {
|
||
// 验证每行的列数
|
||
for i, row := range rows {
|
||
if len(row) != len(handle.Header) {
|
||
return -1, -1, fmt.Errorf("第%d行列数(%d)与表头列数(%d)不匹配", i+1, len(row), len(handle.Header))
|
||
}
|
||
}
|
||
}
|
||
|
||
// 移动到文件末尾
|
||
if _, err := handle.File.Seek(0, 2); err != nil {
|
||
return -1, -1, fmt.Errorf("移动到文件末尾失败: %w", err)
|
||
}
|
||
|
||
// 记录写入前的行数作为起始行号
|
||
// 注意:行号从1开始,如果是首次写入且没有表头,TotalRows=0,起始行号就是1
|
||
startRow := handle.TotalRows + 1
|
||
if handle.HasHeader && startRow == 1 {
|
||
// 如果有表头,数据从第2行开始
|
||
startRow = 2
|
||
}
|
||
|
||
// 批量写入行数据
|
||
for _, row := range rows {
|
||
if err := handle.CSVWriter.Write(row); err != nil {
|
||
return -1, -1, fmt.Errorf("写入行失败: %w", err)
|
||
}
|
||
}
|
||
|
||
// 更新行数统计
|
||
rowsWritten := int64(len(rows))
|
||
handle.TotalRows += rowsWritten
|
||
handle.cachedRowCount = handle.TotalRows
|
||
handle.rowCountCached = true
|
||
|
||
return startRow, rowsWritten, nil
|
||
}
|
||
|
||
// AppendRows 批量追加行数据(自动Flush)
|
||
func (mgr *CSVManager) AppendRowss(handleID int64, rows [][]string) (int64, int64, error) {
|
||
totalRows, rowss, err := mgr.WriteRowss(handleID, rows)
|
||
if err != nil {
|
||
return -1, -1, err
|
||
}
|
||
err = mgr.Flush(handleID)
|
||
if err != nil {
|
||
return -1, -1, err
|
||
}
|
||
return totalRows, rowss, nil
|
||
}
|
||
|
||
// AppendRows 批量追加行数据(自动Flush)
|
||
func (mgr *CSVManager) AppendRowsss(handleID int64, rows [][]string) ([]int64, error) {
|
||
rowsss, err := mgr.WriteRowsss(handleID, rows)
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
err = mgr.Flush(handleID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return rowsss, nil
|
||
}
|
||
|
||
// WriteRows 批量写入多行数据到CSV文件
|
||
// 返回每行数据存储的行号数组(从1开始)
|
||
func (mgr *CSVManager) WriteRowsss(handleID int64, rows [][]string) ([]int64, error) {
|
||
// 首先记录日志
|
||
if err := mgr.logWriteRows(handleID, rows); err != nil {
|
||
// 日志记录失败不影响主流程,但可以打印警告
|
||
fmt.Printf("警告:记录日志失败: %v\n", err)
|
||
}
|
||
|
||
// 获取句柄
|
||
handle, err := mgr.getHandle(handleID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("WriteRows 获取句柄失败: %w", err)
|
||
}
|
||
defer mgr.releaseHandle(handleID)
|
||
|
||
// 检查句柄状态
|
||
if !handle.beginOperation() {
|
||
return nil, fmt.Errorf("句柄已关闭或正在关闭: %d", handleID)
|
||
}
|
||
defer handle.endOperation()
|
||
|
||
handle.mu.Lock()
|
||
defer handle.mu.Unlock()
|
||
|
||
if !handle.IsOpen {
|
||
return nil, fmt.Errorf("文件未打开")
|
||
}
|
||
|
||
// 检查是否有表头
|
||
if handle.HasHeader && len(handle.Header) > 0 {
|
||
// 验证每行的列数
|
||
for i, row := range rows {
|
||
if len(row) != len(handle.Header) {
|
||
return nil, fmt.Errorf("第%d行列数(%d)与表头列数(%d)不匹配", i+1, len(row), len(handle.Header))
|
||
}
|
||
}
|
||
}
|
||
|
||
// 移动到文件末尾
|
||
if _, err := handle.File.Seek(0, 2); err != nil {
|
||
return nil, fmt.Errorf("移动到文件末尾失败: %w", err)
|
||
}
|
||
|
||
// 计算起始行号 - 关键修正部分
|
||
var startRow int64
|
||
|
||
// 先获取当前文件的实际行数(包括表头)
|
||
currentLineCount := handle.TotalRows
|
||
if handle.HasHeader && currentLineCount == 0 {
|
||
// 如果有表头但还没有数据行,表头算第1行,数据从第2行开始
|
||
startRow = 2
|
||
} else if handle.HasHeader {
|
||
// 有表头且已有数据行,表头是第1行,TotalRows不包括表头
|
||
// 所以下一行应该是 TotalRows + 2
|
||
startRow = currentLineCount + 2
|
||
} else {
|
||
// 没有表头,直接累加
|
||
startRow = currentLineCount + 1
|
||
}
|
||
|
||
// 创建行号数组
|
||
rowNumbers := make([]int64, len(rows))
|
||
for i := 0; i < len(rows); i++ {
|
||
rowNumbers[i] = startRow + int64(i)
|
||
}
|
||
|
||
// 批量写入行数据
|
||
for _, row := range rows {
|
||
if err := handle.CSVWriter.Write(row); err != nil {
|
||
return nil, fmt.Errorf("写入行失败: %w", err)
|
||
}
|
||
}
|
||
|
||
// 更新行数统计
|
||
handle.TotalRows += int64(len(rows))
|
||
handle.cachedRowCount = handle.TotalRows
|
||
handle.rowCountCached = true
|
||
|
||
return rowNumbers, nil
|
||
}
|