package main import ( "fmt" ) // //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 }