package main /* #include */ import "C" import ( "bufio" "encoding/csv" "encoding/json" "fmt" "io" "os" "path/filepath" "sync" "sync/atomic" "time" ) // 修改操作类型 type ModifyType int const ( ModifyRow ModifyType = iota // 修改整行 ModifyCell // 修改单元格 InsertRow // 插入行 DeleteRow // 删除行 ) // ModifyRequest 修改请求 type ModifyRequest struct { HandleID int64 // 句柄ID RowNumber int64 // 行号(从1开始) ModifyType ModifyType // 修改类型 NewRow []string // 新行数据(整行修改) NewCellValue string // 新单元格值 ColumnIndex int // 列索引(单元格修改时使用) ColumnName string // 列名(可选,单元格修改时使用) } // ModifyResult 修改结果 type ModifyResult struct { Success bool // 是否成功 Message string // 消息 RowsAffected int64 // 影响的行数 BackupFile string // 备份文件路径 OperationID string // 操作ID(用于追踪) } // RowPosition 行位置信息 type RowPosition struct { StartOffset int64 // 行开始偏移 EndOffset int64 // 行结束偏移 RowLength int // 行长度(字节数) } // CSVHandle CSV文件句柄 type CSVHandle struct { ID int64 // 句柄唯一ID Filename string // 文件名 Delimiter rune // 分隔符 HasHeader bool // 是否有表头 Header []string // 表头(如果有) File *os.File // 底层文件句柄 CSVReader *csv.Reader // CSV阅读器 TotalRows int64 // 总行数(如果已计算) IsOpen bool // 是否已打开 OpenTime time.Time // 打开时间 AccessTime time.Time // 最后访问时间 AccessCount int64 // 访问计数 mu sync.RWMutex // 读写锁(保护数据结构) writeMu sync.Mutex // 写入专用锁(保证写入互斥) autoCloseTimer *time.Timer // 自动关闭计时器 // 修改相关 rowIndex []RowPosition // 行索引(用于快速定位) indexBuilt bool // 索引是否已构建 tempDir string // 临时目录 backupFiles []string // 备份文件列表 operationLog []string // 操作日志 } // CSVManager CSV文件管理器 type CSVManager struct { handles sync.Map // map[int64]*CSVHandle nextHandle int64 // 下一个句柄ID maxOpen int // 最大打开文件数 semaphore chan struct{} // 信号量控制并发打开 config ManagerConfig // 管理器配置 fileLocks *sync.Map // 文件级锁映射 } // ManagerConfig 管理器配置 type ManagerConfig struct { MaxOpenFiles int // 最大打开文件数 AutoCloseTimeout time.Duration // 自动关闭超时 BufferSize int // 缓冲区大小 UseMMap bool // 是否使用内存映射(大文件) MMapThreshold int64 // 使用内存映射的阈值(字节) CacheRows int // 缓存行数 MaxWriteRetries int // 最大写入重试次数 WriteTimeout time.Duration // 写入超时时间 } // DefaultConfig 默认配置 var DefaultConfig = ManagerConfig{ MaxOpenFiles: 100, AutoCloseTimeout: 5 * time.Minute, BufferSize: 32 * 1024, // 32KB UseMMap: true, MMapThreshold: 10 * 1024 * 1024, // 10MB CacheRows: 1000, MaxWriteRetries: 3, WriteTimeout: 30 * time.Second, } // 全局管理器实例 var ( globalManager *CSVManager managerInitOnce sync.Once ) // GetManager 获取全局管理器 func GetManager() *CSVManager { managerInitOnce.Do(func() { globalManager = NewCSVManager(DefaultConfig) }) return globalManager } // NewCSVManager 创建新的CSV管理器 func NewCSVManager(config ManagerConfig) *CSVManager { if config.MaxOpenFiles <= 0 { config.MaxOpenFiles = DefaultConfig.MaxOpenFiles } return &CSVManager{ handles: sync.Map{}, nextHandle: 1, maxOpen: config.MaxOpenFiles, semaphore: make(chan struct{}, config.MaxOpenFiles), config: config, fileLocks: &sync.Map{}, } } // getFileLock 获取文件级锁 func (mgr *CSVManager) getFileLock(filename string) *sync.RWMutex { lock, _ := mgr.fileLocks.LoadOrStore(filename, &sync.RWMutex{}) return lock.(*sync.RWMutex) } // ========================== 文件操作 ========================== // OpenCSVFile 打开CSV文件并返回句柄 func (mgr *CSVManager) OpenCSVFile(filename string, delimiter rune, hasHeader bool) (int64, error) { // 检查文件是否存在 if _, err := os.Stat(filename); os.IsNotExist(err) { return -1, fmt.Errorf("文件不存在: %s", filename) } // 限制并发打开文件数 mgr.semaphore <- struct{}{} defer func() { <-mgr.semaphore }() // 生成唯一句柄ID handleID := atomic.AddInt64(&mgr.nextHandle, 1) // 创建CSV句柄 csvHandle := &CSVHandle{ ID: handleID, Filename: filename, Delimiter: delimiter, HasHeader: hasHeader, OpenTime: time.Now(), AccessTime: time.Now(), } // 打开文件 if err := mgr.openFile(csvHandle); err != nil { return -1, fmt.Errorf("打开文件失败: %w", err) } // 获取总行数 rows, err := csvHandle.GetTotalRows() if err != nil { return -1, err } csvHandle.TotalRows = rows // 读取表头(如果需要) if hasHeader { if err := mgr.readHeader(csvHandle); err != nil { csvHandle.Close() return -1, fmt.Errorf("读取表头失败: %w", err) } } // 注册到管理器 mgr.handles.Store(handleID, csvHandle) // 启动自动关闭计时器 if mgr.config.AutoCloseTimeout > 0 { csvHandle.startAutoClose(mgr.config.AutoCloseTimeout, mgr) } return handleID, nil } // openFile 打开文件 func (mgr *CSVManager) openFile(handle *CSVHandle) error { handle.mu.Lock() defer handle.mu.Unlock() if handle.IsOpen { return nil } // 获取文件大小 fileInfo, err := os.Stat(handle.Filename) if err != nil { return err } fileSize := fileInfo.Size() // 根据文件大小选择打开策略 if mgr.config.UseMMap && fileSize > mgr.config.MMapThreshold { return mgr.openFileWithMMap(handle, fileSize) } return mgr.openFileNormal(handle) } // openFileNormal 正常打开文件 func (mgr *CSVManager) openFileNormal(handle *CSVHandle) error { file, err := os.Open(handle.Filename) if err != nil { return err } // 创建带缓冲的CSV阅读器 reader := csv.NewReader(bufio.NewReaderSize(file, mgr.config.BufferSize)) reader.Comma = handle.Delimiter reader.LazyQuotes = true reader.TrimLeadingSpace = true handle.File = file handle.CSVReader = reader handle.IsOpen = true handle.AccessTime = time.Now() return nil } // openFileWithMMap 使用内存映射打开大文件 func (mgr *CSVManager) openFileWithMMap(handle *CSVHandle, fileSize int64) error { file, err := os.Open(handle.Filename) if err != nil { return err } // 对于大文件,我们可以先只打开,按需读取 reader := csv.NewReader(file) reader.Comma = handle.Delimiter reader.LazyQuotes = true handle.File = file handle.CSVReader = reader handle.IsOpen = true handle.AccessTime = time.Now() return nil } // readHeader 读取CSV表头 func (mgr *CSVManager) readHeader(handle *CSVHandle) error { handle.mu.Lock() defer handle.mu.Unlock() if !handle.IsOpen { return fmt.Errorf("文件未打开") } // 确保文件指针在开头 if _, err := handle.File.Seek(0, 0); err != nil { return err } // 重置CSV阅读器 handle.CSVReader = csv.NewReader(handle.File) handle.CSVReader.Comma = handle.Delimiter // 读取表头 header, err := handle.CSVReader.Read() if err != nil { return err } handle.Header = header return nil } // GetHandle 获取句柄对象 func (mgr *CSVManager) GetHandle(handleID int64) (*CSVHandle, error) { value, ok := mgr.handles.Load(handleID) if !ok { return nil, fmt.Errorf("句柄不存在: %d", handleID) } handle := value.(*CSVHandle) // 确保文件已打开 handle.mu.RLock() isOpen := handle.IsOpen handle.mu.RUnlock() if !isOpen { if err := mgr.openFile(handle); err != nil { return nil, fmt.Errorf("重新打开文件失败: %w", err) } } // 更新访问时间 atomic.AddInt64(&handle.AccessCount, 1) handle.AccessTime = time.Now() return handle, nil } // ========================== 读取操作 ========================== // ReadRow 读取一行数据 func (h *CSVHandle) ReadRow() ([]string, error) { h.mu.RLock() defer h.mu.RUnlock() if !h.IsOpen { return nil, fmt.Errorf("文件未打开") } if h.CSVReader == nil { return nil, fmt.Errorf("CSV阅读器未初始化") } return h.CSVReader.Read() } // ReadAllRows 读取所有行 func (h *CSVHandle) ReadAllRows() ([][]string, error) { h.mu.Lock() defer h.mu.Unlock() if !h.IsOpen { return nil, fmt.Errorf("文件未打开") } // 重置文件指针到数据开始位置 if _, err := h.File.Seek(0, 0); err != nil { return nil, err } // 重新创建CSV阅读器 h.CSVReader = csv.NewReader(h.File) h.CSVReader.Comma = h.Delimiter // 跳过表头 if h.HasHeader { if _, err := h.CSVReader.Read(); err != nil { return nil, err } } // 读取所有行 return h.CSVReader.ReadAll() } // ReadRows 读取指定数量的行 func (h *CSVHandle) ReadRows(count int) ([][]string, error) { h.mu.Lock() defer h.mu.Unlock() if !h.IsOpen { return nil, fmt.Errorf("文件未打开") } rows := make([][]string, 0, count) for i := 0; i < count; i++ { row, err := h.CSVReader.Read() if err == io.EOF { break } if err != nil { return rows, err } rows = append(rows, row) } return rows, nil } // GetTotalRows 获取总行数 func (h *CSVHandle) GetTotalRows() (int64, error) { h.mu.Lock() defer h.mu.Unlock() if h.TotalRows > 0 { return h.TotalRows, nil } // 保存当前文件位置 currentPos, err := h.File.Seek(0, io.SeekCurrent) if err != nil { return 0, err } defer h.File.Seek(currentPos, io.SeekStart) // 重置到文件开始 if _, err := h.File.Seek(0, 0); err != nil { return 0, err } // 创建新的CSV阅读器进行计数 reader := csv.NewReader(h.File) reader.Comma = h.Delimiter var count int64 = 0 // 跳过表头 if h.HasHeader { if _, err := reader.Read(); err != nil { return 0, err } } // 计数行数 for { _, err := reader.Read() if err == io.EOF { break } if err != nil { return count, err } count++ } h.TotalRows = count return count, nil } // ========================== 修改操作 ========================== // ModifyRow 修改指定行 func (mgr *CSVManager) ModifyRow(handleID int64, rowNumber int64, newRow []string) (*ModifyResult, error) { req := &ModifyRequest{ HandleID: handleID, RowNumber: rowNumber, ModifyType: ModifyRow, NewRow: newRow, } return mgr.ModifyCSV(req) } // ModifyCell 修改指定单元格 func (mgr *CSVManager) ModifyCell(handleID int64, rowNumber int64, columnIndex int, newValue string) (*ModifyResult, error) { req := &ModifyRequest{ HandleID: handleID, RowNumber: rowNumber, ModifyType: ModifyCell, ColumnIndex: columnIndex, NewCellValue: newValue, } return mgr.ModifyCSV(req) } // ModifyCSV 通用的CSV修改函数 func (mgr *CSVManager) ModifyCSV(req *ModifyRequest) (*ModifyResult, error) { // 1. 获取句柄 handle, err := mgr.GetHandle(req.HandleID) if err != nil { return &ModifyResult{ Success: false, Message: fmt.Sprintf("获取句柄失败: %v", err), }, err } // 2. 生成操作ID operationID := fmt.Sprintf("%d_%d_%d", req.HandleID, time.Now().UnixNano(), req.RowNumber) // 3. 获取文件级写锁 fileLock := mgr.getFileLock(handle.Filename) fileLock.Lock() defer fileLock.Unlock() // 4. 验证基本参数 if err := mgr.validateModifyRequestBeforeLock(handle, req); err != nil { return &ModifyResult{ Success: false, Message: fmt.Sprintf("参数验证失败: %v", err), }, err } // 5. 获取句柄写入锁 handle.writeMu.Lock() defer handle.writeMu.Unlock() // 6. 执行修改操作 result, err := mgr.executeModifyWithRetry(handle, req, operationID) if result != nil { result.OperationID = operationID } return result, err } // validateModifyRequestBeforeLock 验证修改请求(无需句柄锁) func (mgr *CSVManager) validateModifyRequestBeforeLock(handle *CSVHandle, req *ModifyRequest) error { if req.RowNumber <= 0 { return fmt.Errorf("行号必须大于0") } // 验证列数 handle.mu.RLock() header := handle.Header handle.mu.RUnlock() if req.ModifyType == ModifyRow { expectedCols := len(header) if len(req.NewRow) != expectedCols { return fmt.Errorf("新行数据列数不匹配,期望: %d,实际: %d", expectedCols, len(req.NewRow)) } } if req.ModifyType == ModifyCell { expectedCols := len(header) if req.ColumnIndex < 0 || req.ColumnIndex >= expectedCols { return fmt.Errorf("列索引超出范围,有效范围: 0-%d", expectedCols-1) } } return nil } // executeModifyWithRetry 带重试的修改执行 func (mgr *CSVManager) executeModifyWithRetry(handle *CSVHandle, req *ModifyRequest, operationID string) (*ModifyResult, error) { var lastErr error var result *ModifyResult for retry := 0; retry <= mgr.config.MaxWriteRetries; retry++ { if retry > 0 { // 重试前等待 time.Sleep(time.Duration(retry*100) * time.Millisecond) } result, lastErr = mgr.executeModifyOnce(handle, req, operationID) if lastErr == nil { // 记录操作日志 handle.mu.Lock() handle.operationLog = append(handle.operationLog, fmt.Sprintf("%s: %s", operationID, result.Message)) handle.mu.Unlock() return result, nil } } return &ModifyResult{ Success: false, Message: fmt.Sprintf("修改失败,重试%d次后仍失败: %v", mgr.config.MaxWriteRetries, lastErr), OperationID: operationID, }, lastErr } // executeModifyOnce 执行单次修改 func (mgr *CSVManager) executeModifyOnce(handle *CSVHandle, req *ModifyRequest, operationID string) (*ModifyResult, error) { // 1. 创建备份 backupFile, err := mgr.createBackup(handle) if err != nil { return &ModifyResult{ Success: false, Message: fmt.Sprintf("创建备份失败: %v", err), }, err } // 2. 获取总行数(使用更高效的方式) totalRows, err := mgr.getTotalRowsForModification(handle) if err != nil { return &ModifyResult{ Success: false, Message: fmt.Sprintf("获取总行数失败: %v", err), }, err } //// 2. 获取总行数用于验证 //totalRows, err := mgr.calculateTotalRowsWithLock(handle) //if err != nil { // return &ModifyResult{ // Success: false, // Message: fmt.Sprintf("获取总行数失败: %v", err), // }, err //} // 3. 验证行号范围 if err := mgr.validateRowNumber(handle, req, totalRows); err != nil { return &ModifyResult{ Success: false, Message: fmt.Sprintf("行号验证失败: %v", err), }, err } // 4. 执行修改逻辑 startTime := time.Now() var result *ModifyResult var modifyErr error switch req.ModifyType { case ModifyRow: result, modifyErr = mgr.modifyRowInternal(handle, req, totalRows) case ModifyCell: result, modifyErr = mgr.modifyCellInternal(handle, req, totalRows) case InsertRow: result, modifyErr = mgr.insertRowInternal(handle, req, totalRows) case DeleteRow: result, modifyErr = mgr.deleteRowInternal(handle, req, totalRows) default: modifyErr = fmt.Errorf("不支持的修改类型: %v", req.ModifyType) result = &ModifyResult{ Success: false, Message: fmt.Sprintf("不支持的修改类型: %v", req.ModifyType), } } // 记录执行时间 elapsed := time.Since(startTime) if elapsed > 1*time.Second { fmt.Printf("警告:修改操作耗时较长: %v\n", elapsed) } // 5. 设置备份文件路径 if result != nil { result.BackupFile = backupFile result.OperationID = operationID } // 6. 记录备份文件 if backupFile != "" { handle.mu.Lock() handle.backupFiles = append(handle.backupFiles, backupFile) handle.mu.Unlock() } return result, modifyErr } // getTotalRowsForModification 为修改操作获取总行数(优化版本) func (mgr *CSVManager) getTotalRowsForModification(handle *CSVHandle) (int64, error) { // 先检查是否已有缓存 if handle.TotalRows > 0 { return handle.TotalRows, nil } // 如果文件不大,直接快速计算 fileInfo, err := os.Stat(handle.Filename) if err != nil { return 0, err } // 对于小文件,使用快速计算方法 if fileInfo.Size() < 10*1024*1024 { // 10MB以下 return mgr.fastCountRows(handle) } // 大文件使用原来的方法 return mgr.calculateTotalRowsWithLock(handle) } // fastCountRows 快速计算行数(无需复杂锁) func (mgr *CSVManager) fastCountRows(handle *CSVHandle) (int64, error) { file, err := os.Open(handle.Filename) if err != nil { return 0, err } defer file.Close() reader := csv.NewReader(file) reader.Comma = handle.Delimiter var count int64 = 0 for { _, err := reader.Read() if err == io.EOF { break } if err != nil { return count, err } count++ } // 减去表头行 if handle.HasHeader { count-- } // 缓存结果 handle.mu.Lock() handle.TotalRows = count handle.mu.Unlock() return count, nil } // calculateTotalRowsWithLock 计算总行数(带锁) func (mgr *CSVManager) calculateTotalRowsWithLock(handle *CSVHandle) (int64, error) { handle.mu.Lock() defer handle.mu.Unlock() if handle.TotalRows > 0 { return handle.TotalRows, nil } // 保存当前文件位置 currentPos, err := handle.File.Seek(0, io.SeekCurrent) if err != nil { return 0, err } defer handle.File.Seek(currentPos, io.SeekStart) // 重置到文件开始 if _, err := handle.File.Seek(0, 0); err != nil { return 0, err } // 创建新的CSV阅读器进行计数 reader := csv.NewReader(handle.File) reader.Comma = handle.Delimiter var count int64 = 0 // 跳过表头 if handle.HasHeader { if _, err := reader.Read(); err != nil { return 0, err } } // 计数行数 for { _, err := reader.Read() if err == io.EOF { break } if err != nil { return count, err } count++ } handle.TotalRows = count return count, nil } // validateRowNumber 验证行号 func (mgr *CSVManager) validateRowNumber(handle *CSVHandle, req *ModifyRequest, totalRows int64) error { // 调整行号(考虑表头) adjustedRowNumber := req.RowNumber if handle.HasHeader { adjustedRowNumber = req.RowNumber + 1 // 表头占第1行 } // 验证行号范围 if req.ModifyType == ModifyRow || req.ModifyType == ModifyCell { if adjustedRowNumber > totalRows { return fmt.Errorf("行号超出范围,最大行数为: %d", totalRows-1) } } else if req.ModifyType == InsertRow { // 插入行可以在末尾 if adjustedRowNumber > totalRows+1 { return fmt.Errorf("插入行号超出范围,最大行数为: %d", totalRows) } } else if req.ModifyType == DeleteRow { if adjustedRowNumber > totalRows { return fmt.Errorf("删除行号超出范围,最大行数为: %d", totalRows-1) } } return nil } // createBackup 创建备份文件 func (mgr *CSVManager) createBackup(handle *CSVHandle) (string, error) { handle.mu.RLock() defer handle.mu.RUnlock() // 创建临时目录 if handle.tempDir == "" { tempDir, err := os.MkdirTemp("", fmt.Sprintf("csv_backup_%d_", handle.ID)) if err != nil { return "", fmt.Errorf("创建临时目录失败: %v", err) } handle.tempDir = tempDir } // 生成备份文件名 backupFile := filepath.Join(handle.tempDir, fmt.Sprintf("backup_%d_%s.csv", time.Now().UnixNano(), filepath.Base(handle.Filename))) // 复制文件 src, err := os.Open(handle.Filename) if err != nil { return "", err } defer src.Close() dst, err := os.Create(backupFile) if err != nil { return "", err } defer dst.Close() _, err = io.Copy(dst, src) if err != nil { os.Remove(backupFile) // 删除失败的备份文件 return "", err } return backupFile, nil } // modifyRowInternal 修改整行 func (mgr *CSVManager) modifyRowInternal(handle *CSVHandle, req *ModifyRequest, totalRows int64) (*ModifyResult, error) { // 1. 创建临时文件 tempFile, err := os.CreateTemp(handle.tempDir, "temp_*.csv") if err != nil { return nil, fmt.Errorf("创建临时文件失败: %v", err) } defer func() { tempFile.Close() os.Remove(tempFile.Name()) }() // 2. 复制并修改文件 modifiedCount, err := mgr.copyAndModifyRow(handle, tempFile, req) if err != nil { return nil, fmt.Errorf("复制修改文件失败: %v", err) } // 3. 关闭临时文件以确保数据写入磁盘 if err := tempFile.Close(); err != nil { return nil, fmt.Errorf("关闭临时文件失败: %v", err) } // 4. 原子替换原文件 if err := mgr.atomicReplaceFile(tempFile.Name(), handle.Filename); err != nil { // 尝试恢复备份 mgr.restoreFromBackup(handle) return nil, fmt.Errorf("替换文件失败: %v", err) } // 5. 重新打开文件 handle.mu.Lock() if handle.File != nil { handle.File.Close() handle.File = nil handle.IsOpen = false } if err := mgr.openFile(handle); err != nil { handle.mu.Unlock() return nil, fmt.Errorf("重新打开文件失败: %v", err) } // 更新总行数 handle.TotalRows = totalRows handle.mu.Unlock() return &ModifyResult{ Success: true, Message: fmt.Sprintf("修改第%d行成功", req.RowNumber), RowsAffected: modifiedCount, }, nil } // copyAndModifyRow 复制文件并修改指定行 func (mgr *CSVManager) copyAndModifyRow(handle *CSVHandle, dst *os.File, req *ModifyRequest) (int64, error) { // 打开源文件 src, err := os.Open(handle.Filename) if err != nil { return 0, err } defer src.Close() // 创建CSV读写器 csvReader := csv.NewReader(src) csvReader.Comma = handle.Delimiter csvReader.LazyQuotes = true csvWriter := csv.NewWriter(dst) csvWriter.Comma = handle.Delimiter var rowCount int64 = 0 var modifiedCount int64 = 0 for { row, err := csvReader.Read() if err == io.EOF { break } if err != nil { csvWriter.Flush() return modifiedCount, fmt.Errorf("读取第%d行失败: %v", rowCount+1, err) } rowCount++ // 检查是否是目标行(考虑表头) targetRowNumber := req.RowNumber if handle.HasHeader { targetRowNumber = req.RowNumber + 1 } if rowCount == targetRowNumber { // 修改这一行 row = req.NewRow modifiedCount++ } // 写入行 if err := csvWriter.Write(row); err != nil { csvWriter.Flush() return modifiedCount, fmt.Errorf("写入第%d行失败: %v", rowCount, err) } } // 确保所有数据写入文件 if err := csvWriter.Error(); err != nil { return modifiedCount, fmt.Errorf("CSV写入错误: %v", err) } csvWriter.Flush() return modifiedCount, nil } // modifyCellInternal 修改单元格 func (mgr *CSVManager) modifyCellInternal(handle *CSVHandle, req *ModifyRequest, totalRows int64) (*ModifyResult, error) { // 1. 读取目标行 targetRow, err := mgr.readSpecificRow(handle, req.RowNumber) if err != nil { return nil, fmt.Errorf("读取目标行失败: %v", err) } // 2. 修改单元格 if req.ColumnIndex >= 0 && req.ColumnIndex < len(targetRow) { targetRow[req.ColumnIndex] = req.NewCellValue } else { return nil, fmt.Errorf("列索引超出范围: %d", req.ColumnIndex) } // 3. 构建修改请求(转换为整行修改) rowReq := &ModifyRequest{ HandleID: req.HandleID, RowNumber: req.RowNumber, ModifyType: ModifyRow, NewRow: targetRow, } // 4. 调用整行修改 return mgr.modifyRowInternal(handle, rowReq, totalRows) } // insertRowInternal 插入行 func (mgr *CSVManager) insertRowInternal(handle *CSVHandle, req *ModifyRequest, totalRows int64) (*ModifyResult, error) { // 创建临时文件 tempFile, err := os.CreateTemp(handle.tempDir, "insert_*.csv") if err != nil { return nil, fmt.Errorf("创建临时文件失败: %v", err) } defer func() { tempFile.Close() os.Remove(tempFile.Name()) }() // 打开源文件 src, err := os.Open(handle.Filename) if err != nil { return nil, err } defer src.Close() // 创建CSV读写器 csvReader := csv.NewReader(src) csvReader.Comma = handle.Delimiter csvWriter := csv.NewWriter(tempFile) csvWriter.Comma = handle.Delimiter var rowCount int64 = 0 for { row, err := csvReader.Read() if err == io.EOF { break } if err != nil { csvWriter.Flush() return nil, fmt.Errorf("读取第%d行失败: %v", rowCount+1, err) } rowCount++ // 写入当前行 if err := csvWriter.Write(row); err != nil { csvWriter.Flush() return nil, fmt.Errorf("写入第%d行失败: %v", rowCount, err) } // 检查是否到达插入位置(考虑表头) insertPosition := req.RowNumber if handle.HasHeader { insertPosition = req.RowNumber + 1 } if rowCount == insertPosition { // 插入新行 if err := csvWriter.Write(req.NewRow); err != nil { csvWriter.Flush() return nil, fmt.Errorf("插入新行失败: %v", err) } } } // 如果是最后一行之后插入 adjustedTotalRows := totalRows if handle.HasHeader { adjustedTotalRows = totalRows - 1 } if req.RowNumber == adjustedTotalRows+1 { // 在文件末尾插入 if err := csvWriter.Write(req.NewRow); err != nil { csvWriter.Flush() return nil, fmt.Errorf("在末尾插入新行失败: %v", err) } } // 确保所有数据写入 csvWriter.Flush() if err := csvWriter.Error(); err != nil { return nil, fmt.Errorf("CSV写入错误: %v", err) } // 关闭临时文件 if err := tempFile.Close(); err != nil { return nil, fmt.Errorf("关闭临时文件失败: %v", err) } // 原子替换原文件 handle.mu.Lock() if handle.File != nil { handle.File.Close() handle.File = nil handle.IsOpen = false } if err := mgr.atomicReplaceFile(tempFile.Name(), handle.Filename); err != nil { handle.mu.Unlock() mgr.restoreFromBackup(handle) return nil, fmt.Errorf("替换文件失败: %v", err) } // 重新打开文件 if err := mgr.openFile(handle); err != nil { handle.mu.Unlock() return nil, fmt.Errorf("重新打开文件失败: %v", err) } // 更新总行数 handle.TotalRows = totalRows + 1 handle.mu.Unlock() return &ModifyResult{ Success: true, Message: fmt.Sprintf("在第%d行后插入成功", req.RowNumber), RowsAffected: 1, }, nil } // deleteRowInternal 删除行 func (mgr *CSVManager) deleteRowInternal(handle *CSVHandle, req *ModifyRequest, totalRows int64) (*ModifyResult, error) { // 创建临时文件 tempFile, err := os.CreateTemp(handle.tempDir, "delete_*.csv") if err != nil { return nil, fmt.Errorf("创建临时文件失败: %v", err) } defer func() { tempFile.Close() os.Remove(tempFile.Name()) }() // 打开源文件 src, err := os.Open(handle.Filename) if err != nil { return nil, err } defer src.Close() // 创建CSV读写器 csvReader := csv.NewReader(src) csvReader.Comma = handle.Delimiter csvWriter := csv.NewWriter(tempFile) csvWriter.Comma = handle.Delimiter var rowCount int64 = 0 var deletedCount int64 = 0 for { row, err := csvReader.Read() if err == io.EOF { break } if err != nil { csvWriter.Flush() return nil, fmt.Errorf("读取第%d行失败: %v", rowCount+1, err) } rowCount++ // 检查是否是要删除的行(考虑表头) deleteRowNumber := req.RowNumber if handle.HasHeader { deleteRowNumber = req.RowNumber + 1 } if rowCount == deleteRowNumber { // 跳过这一行(不写入) deletedCount++ continue } // 写入行 if err := csvWriter.Write(row); err != nil { csvWriter.Flush() return nil, fmt.Errorf("写入第%d行失败: %v", rowCount, err) } } // 确保所有数据写入 csvWriter.Flush() if err := csvWriter.Error(); err != nil { return nil, fmt.Errorf("CSV写入错误: %v", err) } // 关闭临时文件 if err := tempFile.Close(); err != nil { return nil, fmt.Errorf("关闭临时文件失败: %v", err) } // 原子替换原文件 handle.mu.Lock() if handle.File != nil { handle.File.Close() handle.File = nil handle.IsOpen = false } if err := mgr.atomicReplaceFile(tempFile.Name(), handle.Filename); err != nil { handle.mu.Unlock() mgr.restoreFromBackup(handle) return nil, fmt.Errorf("替换文件失败: %v", err) } // 重新打开文件 if err := mgr.openFile(handle); err != nil { handle.mu.Unlock() return nil, fmt.Errorf("重新打开文件失败: %v", err) } // 更新总行数 handle.TotalRows = totalRows - deletedCount handle.mu.Unlock() return &ModifyResult{ Success: true, Message: fmt.Sprintf("删除第%d行成功", req.RowNumber), RowsAffected: deletedCount, }, nil } // readSpecificRow 读取指定行 func (mgr *CSVManager) readSpecificRow(handle *CSVHandle, rowNumber int64) ([]string, error) { // 保存当前位置 currentPos, err := handle.File.Seek(0, io.SeekCurrent) if err != nil { return nil, err } defer handle.File.Seek(currentPos, io.SeekStart) // 重置到文件开始 if _, err := handle.File.Seek(0, 0); err != nil { return nil, err } // 创建新的CSV阅读器 reader := csv.NewReader(handle.File) reader.Comma = handle.Delimiter var rowCount int64 = 0 targetRowNumber := rowNumber if handle.HasHeader { targetRowNumber = rowNumber + 1 } for { row, err := reader.Read() if err == io.EOF { break } if err != nil { return nil, err } rowCount++ if rowCount == targetRowNumber { return row, nil } } return nil, fmt.Errorf("行号超出范围: %d", rowNumber) } // ========================== 工具方法 ========================== // atomicReplaceFile 原子替换文件 func (mgr *CSVManager) atomicReplaceFile(src, dst string) error { // 先尝试原子重命名(Unix/Linux上这是原子的) if err := os.Rename(src, dst); err == nil { return nil } // 如果重命名失败(比如Windows或跨分区),使用复制方式 // 创建临时目标文件 tmpDst := dst + ".tmp" if err := mgr.copyFile(src, tmpDst); err != nil { return err } // 重命名为目标文件 if err := os.Rename(tmpDst, dst); err != nil { os.Remove(tmpDst) return err } return nil } // copyFile 复制文件 func (mgr *CSVManager) copyFile(src, dst string) error { source, err := os.Open(src) if err != nil { return err } defer source.Close() destination, err := os.Create(dst) if err != nil { return err } defer destination.Close() _, err = io.Copy(destination, source) return err } // restoreFromBackup 从备份恢复 func (mgr *CSVManager) restoreFromBackup(handle *CSVHandle) error { handle.mu.Lock() defer handle.mu.Unlock() if len(handle.backupFiles) == 0 { return fmt.Errorf("没有可用的备份文件") } // 使用最新的备份 latestBackup := handle.backupFiles[len(handle.backupFiles)-1] // 关闭当前文件 if handle.File != nil { handle.File.Close() handle.File = nil handle.IsOpen = false } // 恢复备份 if err := mgr.atomicReplaceFile(latestBackup, handle.Filename); err != nil { return fmt.Errorf("恢复备份失败: %v", err) } // 重新打开文件 return mgr.openFile(handle) } // ========================== 其他操作 ========================== // GetRow 获取指定行数据 func (mgr *CSVManager) GetRow(handleID int64, rowNumber int64) ([]string, error) { handle, err := mgr.GetHandle(handleID) if err != nil { return nil, err } // 获取文件级读锁 fileLock := mgr.getFileLock(handle.Filename) fileLock.RLock() defer fileLock.RUnlock() return mgr.readSpecificRow(handle, rowNumber) } // UndoLastModify 撤销最后一次修改 func (mgr *CSVManager) UndoLastModify(handleID int64) (*ModifyResult, error) { handle, err := mgr.GetHandle(handleID) if err != nil { return nil, err } // 获取文件级写锁 fileLock := mgr.getFileLock(handle.Filename) fileLock.Lock() defer fileLock.Unlock() handle.mu.Lock() defer handle.mu.Unlock() if len(handle.backupFiles) == 0 { return &ModifyResult{ Success: false, Message: "没有可撤销的修改", }, nil } // 关闭当前文件 if handle.File != nil { handle.File.Close() handle.File = nil handle.IsOpen = false } // 获取最新的备份 latestBackup := handle.backupFiles[len(handle.backupFiles)-1] // 恢复文件 if err := mgr.atomicReplaceFile(latestBackup, handle.Filename); err != nil { return &ModifyResult{ Success: false, Message: fmt.Sprintf("恢复文件失败: %v", err), }, err } // 重新打开文件 if err := mgr.openFile(handle); err != nil { return &ModifyResult{ Success: false, Message: fmt.Sprintf("重新打开文件失败: %v", err), }, err } // 移除已使用的备份 handle.backupFiles = handle.backupFiles[:len(handle.backupFiles)-1] // 重新计算总行数 totalRows, _ := mgr.calculateTotalRowsWithLock(handle) fmt.Printf("总行数: %d\n", totalRows) return &ModifyResult{ Success: true, Message: "撤销成功", RowsAffected: 1, BackupFile: latestBackup, }, nil } // CleanupBackups 清理备份文件 func (mgr *CSVManager) CleanupBackups(handleID int64) error { handle, err := mgr.GetHandle(handleID) if err != nil { return err } handle.mu.Lock() defer handle.mu.Unlock() // 清理所有备份文件 for _, backupFile := range handle.backupFiles { os.Remove(backupFile) } handle.backupFiles = nil // 清理临时目录 if handle.tempDir != "" { os.RemoveAll(handle.tempDir) handle.tempDir = "" } return nil } // ========================== 句柄管理 ========================== // Close 关闭CSV句柄 func (h *CSVHandle) Close() error { h.mu.Lock() defer h.mu.Unlock() h.writeMu.Lock() defer h.writeMu.Unlock() if !h.IsOpen { return nil } // 停止自动关闭计时器 if h.autoCloseTimer != nil { h.autoCloseTimer.Stop() h.autoCloseTimer = nil } // 关闭文件 if h.File != nil { if err := h.File.Close(); err != nil { return err } h.File = nil } h.CSVReader = nil h.IsOpen = false return nil } // startAutoClose 启动自动关闭计时器 func (h *CSVHandle) startAutoClose(timeout time.Duration, mgr *CSVManager) { h.autoCloseTimer = time.AfterFunc(timeout, func() { h.mu.Lock() defer h.mu.Unlock() // 检查是否长时间未访问 if h.IsOpen && time.Since(h.AccessTime) > timeout { h.Close() // 从管理器移除 mgr.handles.Delete(h.ID) } }) } // GetHeader 获取表头 func (h *CSVHandle) GetHeader() []string { h.mu.RLock() defer h.mu.RUnlock() return h.Header } // GetInfo 获取句柄信息 func (h *CSVHandle) GetInfo() map[string]interface{} { h.mu.RLock() defer h.mu.RUnlock() return map[string]interface{}{ "id": h.ID, "filename": h.Filename, "delimiter": string(h.Delimiter), "has_header": h.HasHeader, "is_open": h.IsOpen, "open_time": h.OpenTime, "access_time": h.AccessTime, "access_count": h.AccessCount, "total_rows": h.TotalRows, "header": h.Header, } } // CloseHandle 关闭指定句柄 func (mgr *CSVManager) CloseHandle(handleID int64) error { value, ok := mgr.handles.Load(handleID) if !ok { return fmt.Errorf("句柄不存在: %d", handleID) } handle := value.(*CSVHandle) if err := handle.Close(); err != nil { return err } // 清理文件锁 mgr.fileLocks.Delete(handle.Filename) mgr.handles.Delete(handleID) return nil } // CloseAllHandles 关闭所有句柄 func (mgr *CSVManager) CloseAllHandles() { mgr.handles.Range(func(key, value interface{}) bool { handle := value.(*CSVHandle) handle.Close() mgr.fileLocks.Delete(handle.Filename) mgr.handles.Delete(key) return true }) } // ========================== 简便函数 ========================== //// OpenCSVFile 打开CSV文件 //func OpenCSVFile(filename string, delimiter rune, hasHeader bool) (int64, error) { // return GetManager().OpenCSVFile(filename, delimiter, hasHeader, "utf-8") //} // GetCSVHandle 获取CSV句柄 func GetCSVHandle(handleID int64) (*CSVHandle, error) { return GetManager().GetHandle(handleID) } // CloseCSVHandle 关闭CSV句柄 func CloseCSVHandle(handleID int64) error { return GetManager().CloseHandle(handleID) } // ModifyCSVRow 修改CSV行 func ModifyCSVRow(handleID int64, rowNumber int64, newRow []string) (*ModifyResult, error) { return GetManager().ModifyRow(handleID, rowNumber, newRow) } // ModifyCSVCell 修改CSV单元格 func ModifyCSVCell(handleID int64, rowNumber int64, columnIndex int, newValue string) (*ModifyResult, error) { return GetManager().ModifyCell(handleID, rowNumber, columnIndex, newValue) } // GetCSVRow 获取CSV行 func GetCSVRow(handleID int64, rowNumber int64) ([]string, error) { return GetManager().GetRow(handleID, rowNumber) } // UndoLastCSVModify 撤销最后修改 func UndoLastCSVModify(handleID int64) (*ModifyResult, error) { return GetManager().UndoLastModify(handleID) } // CleanupCSVBackups 清理CSV备份 func CleanupCSVBackups(handleID int64) error { return GetManager().CleanupBackups(handleID) } // UpdateCSVRowSafe 修改csv文件行数据 func (mgr *CSVManager) UpdateCSVRowSafe(handleID int64, rowNum int, newRow []string) error { getHandle, err := mgr.GetHandle(handleID) if err != nil { return fmt.Errorf("获取句柄信息失败: %v", err) } // 1. 创建临时文件 tempDir := filepath.Dir(getHandle.Filename) if tempDir == "" { tempDir = "." } tempFile, err := os.CreateTemp(tempDir, "temp_*.csv") if err != nil { return fmt.Errorf("创建临时文件失败: %v", err) } tempFileName := tempFile.Name() // 确保临时文件被关闭和清理 defer func() { tempFile.Close() // 如果临时文件还存在(替换失败),则清理它 if _, err := os.Stat(tempFileName); err == nil { os.Remove(tempFileName) } }() // 2. 读取原始文件 sourceFile, err := os.Open(getHandle.Filename) if err != nil { return fmt.Errorf("打开源文件失败: %v", err) } defer sourceFile.Close() // 3. 读取并处理数据 reader := csv.NewReader(sourceFile) allRows, err := reader.ReadAll() if err != nil { return fmt.Errorf("读取CSV失败: %v", err) } // 4. 验证并更新 if rowNum < 1 || rowNum > len(allRows) { return fmt.Errorf("行号 %d 超出范围 (1-%d)", rowNum, len(allRows)) } // 显示修改前后的对比 oldRow := allRows[rowNum-1] fmt.Printf("修改前第 %d 行: %v\n", rowNum, oldRow) fmt.Printf("修改后第 %d 行: %v\n", rowNum, newRow) allRows[rowNum-1] = newRow // 5. 写入临时文件 writer := csv.NewWriter(tempFile) if err := writer.WriteAll(allRows); err != nil { return fmt.Errorf("写入临时文件失败: %v", err) } writer.Flush() if err := writer.Error(); err != nil { return fmt.Errorf("刷新写入失败: %v", err) } // 6. 确保数据写入磁盘 if err := tempFile.Sync(); err != nil { return fmt.Errorf("同步文件失败: %v", err) } tempFile.Close() // 7. 使用复制而不是重命名(解决Windows文件占用问题) if err := copyFile(tempFileName, getHandle.Filename); err != nil { return fmt.Errorf("复制文件失败: %v", err) } fmt.Printf("✅ 成功更新第 %d 行,文件已直接更新\n", rowNum) return nil } // copyFile 复制文件内容 func copyFile(src, dst string) error { // 打开源文件 source, err := os.Open(src) if err != nil { return err } defer source.Close() // 创建目标文件 destination, err := os.Create(dst) if err != nil { return err } defer destination.Close() // 复制内容 _, err = io.Copy(destination, source) if err != nil { return err } // 确保数据写入磁盘 err = destination.Sync() if err != nil { return err } return nil } // CSV响应结构体 type CSVResponse struct { Success bool `json:"success"` Message string `json:"message,omitempty"` Data interface{} `json:"data,omitempty"` } // ===================== C 函数导入 ================== // OpenCSVFile 打开/创建CSV文件 // //export OpenCSVFile func OpenCSVFile(filename *C.char, delimiter C.char, hasHeader C.int) *C.char { goFilename := C.GoString(filename) goDelimiter := rune(delimiter) var hasHeaderBool bool if hasHeader != 0 { hasHeaderBool = true } hasHeaderBool = false handle, err := GetManager().OpenCSVFile(goFilename, goDelimiter, hasHeaderBool) response := struct { Handle int64 `json:"handle"` }{ Handle: handle, } var csvResponse CSVResponse if err != nil { csvResponse = CSVResponse{ Success: false, Message: err.Error(), } } else { csvResponse = CSVResponse{ Success: true, Data: response, } } // 转换为JSON字符串 jsonData, err := json.Marshal(csvResponse) if err != nil { // 如果JSON序列化失败,返回错误信息 csvResponse = CSVResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", err), } errorJson, _ := json.Marshal(csvResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // UpdateCSVRowSafe 修改csv文件行数据 // //export UpdateCSVRowSafe func UpdateCSVRowSafe(handleID C.longlong, rowNum C.int, newRow *C.char) *C.char { goHandle := int64(handleID) goRowNum := int(rowNum) goNewRow := C.GoString(newRow) var row []string var csvResponse CSVResponse // 解析JSON err := json.Unmarshal([]byte(goNewRow), &row) if err != nil { csvResponse = CSVResponse{ Success: false, Message: fmt.Sprintf("解析JSON失败: %v", err), } errorJson, _ := json.Marshal(csvResponse) return C.CString(string(errorJson)) } // 修改csv行数据 err = GetManager().UpdateCSVRowSafe(goHandle, goRowNum, row) if err != nil { csvResponse = CSVResponse{ Success: false, Message: fmt.Sprintf(err.Error()), } errorJson, _ := json.Marshal(csvResponse) return C.CString(string(errorJson)) } else { csvResponse = CSVResponse{ Success: true, } } // 转换为JSON字符串 jsonData, err := json.Marshal(csvResponse) if err != nil { // 如果JSON序列化失败,返回错误信息 csvResponse = CSVResponse{ Success: false, Message: fmt.Sprintf("JSON序列化失败: %v", err), } errorJson, _ := json.Marshal(csvResponse) return C.CString(string(errorJson)) } return C.CString(string(jsonData)) } // 主函数 func main() { //fmt.Println("=== CSV句柄管理器测试 ===") // //filename := "csv/taskLog.csv" //fmt.Printf("1. 创建测试文件: %s\n", filename) // //// 2. 打开CSV文件 //handleID, err := OpenCSVFile(filename, ',', true) //if err != nil { // fmt.Printf("打开文件失败: %v\n", err) // return //} //defer CloseCSVHandle(handleID) // //fmt.Printf("2. 打开文件成功,句柄ID: %d\n", handleID) // ////// 3. 获取句柄信息 ////handle, err := GetCSVHandle(handleID) ////if err != nil { //// fmt.Printf("获取句柄失败: %v\n", err) //// return ////} //// ////info := handle.GetInfo() ////fmt.Printf("3. 文件信息:\n") ////fmt.Printf(" - 文件名: %s\n", info["filename"]) ////fmt.Printf(" - 总行数: %v\n", info["total_rows"]) ////fmt.Printf(" - 表头: %v\n", info["header"]) // ////// 准备新的行数据 ////newData := []string{"9787115524539", "20.00", "20", "上传成功", ""} ////err = UpdateCSVRowSafes(handleID, 6, newData) ////if err != nil { //// fmt.Printf("错误: %v\n", err) ////} else { //// fmt.Println("CSV文件更新成功!") ////} // //// 4. 读取数据 //fmt.Println("4. 读取测试:") //row3, err := GetCSVRow(handleID, 100000) //if err != nil { // fmt.Printf(" 读取第100000行失败: %v\n", err) //} else { // fmt.Printf(" 第100000行数据: %v\n", row3) //} // ////// 5. 修改测试 ////fmt.Println("5. 修改测试:") ////newRow := []string{"9787115524539", "20.00", "1", "上传成功", ""} ////result, err := ModifyCSVRow(handleID, 3, newRow) ////if err != nil { //// fmt.Printf(" 修改失败: %v\n", err) ////} else { //// fmt.Printf(" 修改结果: %s (影响行数: %d)\n", result.Message, result.RowsAffected) //// //// // 验证修改 //// modifiedRow, _ := GetCSVRow(handleID, 3) //// fmt.Printf(" 修改后的第3行: %v\n", modifiedRow) ////} // ////// 6. 单元格修改测试 ////fmt.Println("6. 单元格修改测试:") ////cellResult, err := ModifyCSVCell(handleID, 5, 1, "35") ////if err != nil { //// fmt.Printf(" 单元格修改失败: %v\n", err) ////} else { //// fmt.Printf(" 单元格修改结果: %s\n", cellResult.Message) //// //// // 验证修改 //// cellModifiedRow, _ := GetCSVRow(handleID, 5) //// fmt.Printf(" 修改后的第5行: %v\n", cellModifiedRow) ////} //// ////// 7. 并发测试 ////fmt.Println("7. 并发测试:") ////TestConcurrentOperations(handleID) //// ////fmt.Println("=== 测试完成 ===") } // 下面是一个更简单的版本,根据你的具体需求可以选择使用 func WriteCSVSimple(filename string, data [][]string) error { if len(data) == 0 { return fmt.Errorf("写入的数据不能为空") } var file *os.File var err error var fileMode int // 检查文件是否存在和有内容 if info, err := os.Stat(filename); err == nil && info.Size() > 0 { // 文件存在且有内容,追加模式 fileMode = os.O_APPEND | os.O_WRONLY } else { // 文件不存在或为空,创建模式(会清空已有内容) fileMode = os.O_CREATE | os.O_WRONLY | os.O_TRUNC } // 打开或创建文件 file, err = os.OpenFile(filename, fileMode, 0755) if err != nil { return err } defer file.Close() // 写入CSV数据 writer := csv.NewWriter(file) if err := writer.WriteAll(data); err != nil { return err } writer.Flush() return writer.Error() }