daShangDao_kfzgw-info/csv/csvDll.go
97694732@qq.com ac2a39742d 各种修改
2026-06-11 13:21:55 +08:00

1074 lines
29 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}