package main import ( "context" "fmt" "github.com/redis/go-redis/v9" "log" ) // //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/test1.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. 获取修改后的行数据") //获取第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测试完成!") }