package main /* #include */ import "C" import ( "encoding/csv" "encoding/json" "fmt" "github.com/xuri/excelize/v2" "os" "path/filepath" "sort" "strings" "sync" "unsafe" ) // ExcelManager 线程安全的Excel文件管理器 type ExcelManager struct { mu sync.RWMutex fileMap map[string]*excelize.File // 存储打开的文件 } // MergeConfig 合并配置 type MergeConfig struct { SourceDir string // 源目录 OutputFile string // 输出文件 SheetName string // 目标sheet名称 MergeByColumn bool // 是否按列合并(默认按行) IncludeHeaders bool // 是否包含表头(仅第一个文件) SkipEmptyRows bool // 是否跳过空行 FilePattern string // 文件匹配模式,如 "*.xlsx" SpecificFiles []string // 指定要合并的文件列表 SourceSheet string // 源sheet名称(为空则使用第一个sheet) AddSourceColumn bool // 是否添加源文件列 AddIndexColumn bool // 是否添加序号列 } // NewExcelManager 创建新的Excel管理器 func NewExcelManager() *ExcelManager { return &ExcelManager{ fileMap: make(map[string]*excelize.File), } } // ============ 基本Excel操作功能 ============ // ReadData 读取Excel数据 func (em *ExcelManager) ReadData(filename, sheet string) ([][]string, error) { em.mu.RLock() defer em.mu.RUnlock() fmt.Printf("[DEBUG] ReadData开始: file=%s, sheet=%s\n", filename, sheet) file, err := excelize.OpenFile(filename) if err != nil { return nil, err } defer file.Close() rows, err := file.GetRows(sheet) if err != nil { return nil, fmt.Errorf("读取sheet %s 失败: %v", sheet, err) } fmt.Printf("[DEBUG] 读取的数据:", rows) return rows, nil } // WriteData 写入数据到指定位置 func (em *ExcelManager) WriteData(filename, sheet string, data map[string]interface{}) error { em.mu.Lock() defer em.mu.Unlock() file, err := excelize.OpenFile(filename) if err != nil { // 文件不存在,创建新文件 file = excelize.NewFile() file.NewSheet(sheet) } else { // 确保sheet存在 index, _ := file.GetSheetIndex(sheet) if index == -1 { file.NewSheet(sheet) } } // 写入数据 for cell, value := range data { file.SetCellValue(sheet, cell, value) } // 保存文件 return file.SaveAs(filename) } // AppendData 追加数据到末尾 func (em *ExcelManager) AppendData(filename, sheet string, rowData []interface{}) error { em.mu.Lock() defer em.mu.Unlock() file, err := excelize.OpenFile(filename) if err != nil { return err } defer func() { file.SaveAs(filename) file.Close() }() // 确保sheet存在 index, _ := file.GetSheetIndex(sheet) if index == -1 { file.NewSheet(sheet) } // 获取当前最大行号 rows, err := file.GetRows(sheet) if err != nil { return err } nextRow := len(rows) + 1 if len(rows) == 0 { nextRow = 1 } // 写入新行 for col, value := range rowData { cell, _ := excelize.CoordinatesToCellName(col+1, nextRow) file.SetCellValue(sheet, cell, value) } return nil } // SearchByKeyword 搜索包含关键字的单元格 func (em *ExcelManager) SearchByKeyword(filename, sheet, keyword string) ([]string, error) { em.mu.RLock() defer em.mu.RUnlock() file, err := excelize.OpenFile(filename) if err != nil { return nil, err } defer file.Close() var results []string rows, err := file.GetRows(sheet) if err != nil { return nil, err } for rowIndex, row := range rows { for colIndex, cell := range row { if strings.Contains(cell, keyword) { cellName, _ := excelize.CoordinatesToCellName(colIndex+1, rowIndex+1) results = append(results, fmt.Sprintf("位置: %s, 值: %s", cellName, cell)) } } } return results, nil } // SearchRowData 搜索整行包含关键字的行 func (em *ExcelManager) SearchRowData(filename, sheet, keyword string) ([][]string, error) { em.mu.RLock() defer em.mu.RUnlock() file, err := excelize.OpenFile(filename) if err != nil { return nil, err } defer file.Close() var results [][]string rows, err := file.GetRows(sheet) if err != nil { return nil, err } for _, row := range rows { for _, cell := range row { if strings.Contains(cell, keyword) { results = append(results, row) break } } } return results, nil } // CreateAndWrite 创建新文件并写入数据 func (em *ExcelManager) CreateAndWrite(filename, sheet string, data [][]string) error { em.mu.Lock() defer em.mu.Unlock() // 创建新文件 file := excelize.NewFile() defer file.Close() // 如果指定sheet不是"Sheet1",则重命名默认sheet if sheet != "Sheet1" { file.SetSheetName("Sheet1", sheet) } // 写入数据 for rowIndex, row := range data { for colIndex, value := range row { cell, _ := excelize.CoordinatesToCellName(colIndex+1, rowIndex+1) file.SetCellValue(sheet, cell, value) } } // 保存文件 return file.SaveAs(filename) } // CloseAll 关闭所有文件 func (em *ExcelManager) CloseAll() error { em.mu.Lock() defer em.mu.Unlock() var lastErr error for filename, file := range em.fileMap { if err := file.Close(); err != nil { lastErr = err } delete(em.fileMap, filename) } return lastErr } // ============ Excel合并功能 ============ // MergeExcelFiles 合并多个Excel文件(批次合并) func (em *ExcelManager) MergeExcelFiles(config MergeConfig) error { em.mu.Lock() defer em.mu.Unlock() // 获取要合并的文件列表 filesToMerge, err := em.getFilesToMerge(config) if err != nil { return err } fmt.Printf("开始合并 %d 个文件:\n", len(filesToMerge)) for i, file := range filesToMerge { fmt.Printf(" %d. %s\n", i+1, filepath.Base(file)) } // 创建新的输出文件 outputFile := excelize.NewFile() defer outputFile.Close() // 删除默认的Sheet1 outputFile.DeleteSheet("Sheet1") // 创建目标sheet并设置为活动sheet sheetIndex, err := outputFile.NewSheet(config.SheetName) if err != nil { return fmt.Errorf("创建sheet失败: %v", err) } outputFile.SetActiveSheet(sheetIndex) currentRow := 1 totalRowsMerged := 0 fileCount := len(filesToMerge) // 写入表头(如果需要) if config.IncludeHeaders && fileCount > 0 { headers, err := em.readFileHeaders(filesToMerge[0], config.SourceSheet) if err != nil { fmt.Printf("警告: 无法读取第一个文件的表头: %v\n", err) } else { // 添加额外的列(如果需要) colOffset := 0 if config.AddIndexColumn { headers = append([]string{"序号"}, headers...) colOffset++ } if config.AddSourceColumn { headers = append([]string{"源文件"}, headers...) colOffset++ } // 写入表头 for colIndex, header := range headers { cellName, _ := excelize.CoordinatesToCellName(colIndex+1, currentRow) outputFile.SetCellValue(config.SheetName, cellName, header) } currentRow++ fmt.Printf("写入表头: %v\n", headers) } } // 合并所有文件 for fileIndex, sourceFile := range filesToMerge { rowsMerged, err := em.mergeSingleFile(outputFile, config, sourceFile, fileIndex, fileCount, ¤tRow) if err != nil { fmt.Printf("警告: 合并文件 %s 时出错: %v,跳过\n", sourceFile, err) continue } totalRowsMerged += rowsMerged } // 保存输出文件 if err := outputFile.SaveAs(config.OutputFile); err != nil { return fmt.Errorf("保存合并文件失败: %v", err) } fmt.Printf("合并完成!结果保存在: %s\n", config.OutputFile) fmt.Printf("统计信息:\n") fmt.Printf(" - 合并文件数: %d\n", fileCount) fmt.Printf(" - 合并数据行数: %d\n", totalRowsMerged) fmt.Printf(" - 输出文件总行数: %d\n", currentRow-1) // 验证文件是否正确保存 if err := em.verifyMergeResult(config.OutputFile, config.SheetName); err != nil { return fmt.Errorf("合并结果验证失败: %v", err) } return nil } // getFilesToMerge 获取要合并的文件列表 func (em *ExcelManager) getFilesToMerge(config MergeConfig) ([]string, error) { var filesToMerge []string if len(config.SpecificFiles) > 0 { filesToMerge = config.SpecificFiles } else if config.SourceDir != "" { pattern := "*.xlsx" if config.FilePattern != "" { pattern = config.FilePattern } files, err := filepath.Glob(filepath.Join(config.SourceDir, pattern)) if err != nil { return nil, fmt.Errorf("查找文件失败: %v", err) } filesToMerge = files } else { return nil, fmt.Errorf("必须指定SourceDir或SpecificFiles") } if len(filesToMerge) == 0 { return nil, fmt.Errorf("没有找到要合并的Excel文件") } // 按文件名排序 sort.Strings(filesToMerge) return filesToMerge, nil } // readFileHeaders 读取文件的表头 func (em *ExcelManager) readFileHeaders(filename, sheetName string) ([]string, error) { srcFile, err := excelize.OpenFile(filename) if err != nil { return nil, err } defer srcFile.Close() sourceSheet := em.getSourceSheet(srcFile, sheetName) if sourceSheet == "" { return nil, fmt.Errorf("未找到可用的sheet") } rows, err := srcFile.GetRows(sourceSheet) if err != nil { return nil, err } if len(rows) == 0 { return nil, fmt.Errorf("文件没有数据") } return rows[0], nil } // mergeSingleFile 合并单个文件 func (em *ExcelManager) mergeSingleFile(outputFile *excelize.File, config MergeConfig, sourceFile string, fileIndex, fileCount int, currentRow *int) (int, error) { fmt.Printf("\n[%d/%d] 正在处理文件: %s\n", fileIndex+1, fileCount, filepath.Base(sourceFile)) // 打开源文件 srcFile, err := excelize.OpenFile(sourceFile) if err != nil { return 0, fmt.Errorf("打开文件失败: %v", err) } defer srcFile.Close() // 确定要读取的sheet sourceSheet := em.getSourceSheet(srcFile, config.SourceSheet) if sourceSheet == "" { return 0, fmt.Errorf("未找到可用的sheet") } // 读取源文件数据 rows, err := srcFile.GetRows(sourceSheet) if err != nil { return 0, fmt.Errorf("读取数据失败: %v", err) } if len(rows) == 0 { fmt.Printf(" 警告: 文件没有数据,跳过\n") return 0, nil } fmt.Printf(" 读取到 %d 行数据\n", len(rows)) rowsMerged := 0 // 处理数据行 for rowIndex, row := range rows { // 跳过空行 if config.SkipEmptyRows && em.isRowEmpty(row) { continue } fmt.Println(rowIndex) // 处理表头(如果是第一个文件且包含表头,第一行已经处理过了) if config.IncludeHeaders && rowIndex == 0 { if fileIndex == 0 { // 第一个文件的表头已处理,跳过 continue } else { // 后续文件的表头跳过 continue } } // 写入数据行 colOffset := 0 // 添加序号列 if config.AddIndexColumn { cellName, _ := excelize.CoordinatesToCellName(1, *currentRow) outputFile.SetCellValue(config.SheetName, cellName, rowsMerged+1) colOffset++ } // 添加源文件列 if config.AddSourceColumn { cellName, _ := excelize.CoordinatesToCellName(1+colOffset, *currentRow) outputFile.SetCellValue(config.SheetName, cellName, filepath.Base(sourceFile)) colOffset++ } // 写入原始数据 for colIndex, cell := range row { cellName, _ := excelize.CoordinatesToCellName(colIndex+1+colOffset, *currentRow) outputFile.SetCellValue(config.SheetName, cellName, cell) } rowsMerged++ *currentRow++ } //// 添加文件分隔信息(如果有数据被合并) //if rowsMerged > 0 { // // 添加分隔行 // separatorCell, _ := excelize.CoordinatesToCellName(1, *currentRow) // outputFile.SetCellValue(config.SheetName, separatorCell, // fmt.Sprintf("=== 文件 %d/%d: %s (合并了 %d 行) ===", // fileIndex+1, fileCount, filepath.Base(sourceFile), rowsMerged)) // *currentRow++ //} fmt.Printf(" 文件处理完成,合并了 %d 行数据\n", rowsMerged) return rowsMerged, nil } // getSourceSheet 获取源sheet名称 func (em *ExcelManager) getSourceSheet(file *excelize.File, preferredSheet string) string { if preferredSheet != "" { if index, _ := file.GetSheetIndex(preferredSheet); index != -1 { return preferredSheet } } // 返回第一个sheet sheets := file.GetSheetList() if len(sheets) > 0 { return sheets[0] } return "" } // verifyMergeResult 验证合并结果 func (em *ExcelManager) verifyMergeResult(filename, sheet string) error { file, err := excelize.OpenFile(filename) if err != nil { return fmt.Errorf("打开验证文件失败: %v", err) } defer file.Close() rows, err := file.GetRows(sheet) if err != nil { return fmt.Errorf("读取sheet失败: %v", err) } fmt.Printf("\n验证结果:\n") fmt.Printf(" 文件: %s\n", filename) fmt.Printf(" Sheet: %s\n", sheet) fmt.Printf(" 总行数: %d\n", len(rows)) if len(rows) == 0 { return fmt.Errorf("警告: 合并后的文件没有数据!") } // 显示前5行数据 limit := 5 if len(rows) < limit { limit = len(rows) } fmt.Printf(" 前%d行数据预览:\n", limit) for i := 0; i < limit; i++ { // 只显示前5列(避免输出过长) previewCols := 5 if len(rows[i]) < previewCols { previewCols = len(rows[i]) } fmt.Printf(" 第%d行: %v", i+1, rows[i][:previewCols]) if len(rows[i]) > previewCols { fmt.Printf(" ... (+%d列)", len(rows[i])-previewCols) } fmt.Println() } return nil } // MergeExcelFilesParallel 并行合并Excel文件(高性能) func (em *ExcelManager) MergeExcelFilesParallel(config MergeConfig, workers int) error { em.mu.Lock() defer em.mu.Unlock() // 获取要合并的文件列表 filesToMerge, err := em.getFilesToMerge(config) if err != nil { return err } fmt.Printf("开始并行合并 %d 个文件,使用 %d 个worker:\n", len(filesToMerge), workers) // 创建通道和等待组 fileChan := make(chan fileTask, len(filesToMerge)) resultChan := make(chan fileResult, len(filesToMerge)) var wg sync.WaitGroup // 启动worker goroutines for i := 0; i < workers; i++ { wg.Add(1) go func(workerID int) { defer wg.Done() for task := range fileChan { fmt.Printf("Worker %d 正在处理: %s (文件 %d/%d)\n", workerID, filepath.Base(task.filename), task.index+1, task.total) data := em.readExcelFileParallel(task.filename, config.SourceSheet) resultChan <- fileResult{ filename: task.filename, index: task.index, data: data, } } }(i) } // 发送文件任务到通道 for i, file := range filesToMerge { fileChan <- fileTask{ filename: file, index: i, total: len(filesToMerge), } } close(fileChan) // 等待所有worker完成 go func() { wg.Wait() close(resultChan) }() // 收集结果 var results []fileResult for result := range resultChan { results = append(results, result) } // 按文件索引排序 sort.Slice(results, func(i, j int) bool { return results[i].index < results[j].index }) // 创建新的输出文件 outputFile := excelize.NewFile() defer outputFile.Close() // 删除默认的Sheet1 outputFile.DeleteSheet("Sheet1") // 创建目标sheet sheetIndex, err := outputFile.NewSheet(config.SheetName) if err != nil { return fmt.Errorf("创建sheet失败: %v", err) } outputFile.SetActiveSheet(sheetIndex) // 合并数据 currentRow := 1 totalRowsMerged := 0 // 写入表头(如果需要) headersWritten := false if config.IncludeHeaders && len(results) > 0 { for _, result := range results { if result.data.err == nil && len(result.data.rows) > 0 { headers := result.data.rows[0] // 添加额外的列 colOffset := 0 if config.AddIndexColumn { headers = append([]string{"序号"}, headers...) colOffset++ } if config.AddSourceColumn { headers = append([]string{"源文件"}, headers...) colOffset++ } // 写入表头 for colIndex, header := range headers { cellName, _ := excelize.CoordinatesToCellName(colIndex+1, currentRow) outputFile.SetCellValue(config.SheetName, cellName, header) } currentRow++ headersWritten = true fmt.Printf("写入表头: %v\n", headers) break // 只取第一个有效文件的表头 } } } // 写入数据 for _, result := range results { if result.data.err != nil { fmt.Printf("警告: 文件 %s 处理失败: %v,跳过\n", result.filename, result.data.err) continue } if len(result.data.rows) == 0 { fmt.Printf("警告: 文件 %s 没有数据,跳过\n", result.filename) continue } rowsMerged := 0 for rowIndex, row := range result.data.rows { // 跳过表头(如果已经处理过) if config.IncludeHeaders && rowIndex == 0 && headersWritten { continue } // 跳过空行 if config.SkipEmptyRows && em.isRowEmpty(row) { continue } // 写入数据行 colOffset := 0 // 添加序号列 if config.AddIndexColumn { cellName, _ := excelize.CoordinatesToCellName(1, currentRow) outputFile.SetCellValue(config.SheetName, cellName, totalRowsMerged+1) colOffset++ } // 添加源文件列 if config.AddSourceColumn { cellName, _ := excelize.CoordinatesToCellName(1+colOffset, currentRow) outputFile.SetCellValue(config.SheetName, cellName, filepath.Base(result.filename)) colOffset++ } // 写入原始数据 for colIndex, cell := range row { cellName, _ := excelize.CoordinatesToCellName(colIndex+1+colOffset, currentRow) outputFile.SetCellValue(config.SheetName, cellName, cell) } currentRow++ rowsMerged++ totalRowsMerged++ } //// 添加分隔行 //if rowsMerged > 0 { // separatorCell, _ := excelize.CoordinatesToCellName(1, currentRow) // outputFile.SetCellValue(config.SheetName, separatorCell, // fmt.Sprintf("=== 文件 %d/%d: %s ===", // result.index+1, len(results), filepath.Base(result.filename))) // currentRow++ //} } // 保存输出文件 if err := outputFile.SaveAs(config.OutputFile); err != nil { return fmt.Errorf("保存合并文件失败: %v", err) } fmt.Printf("并行合并完成!结果保存在: %s\n", config.OutputFile) fmt.Printf("统计信息:\n") fmt.Printf(" - 合并文件数: %d\n", len(results)) fmt.Printf(" - 合并数据行数: %d\n", totalRowsMerged) return em.verifyMergeResult(config.OutputFile, config.SheetName) } // MergeByColumn 按列合并Excel文件 func (em *ExcelManager) MergeByColumn(config MergeConfig) error { em.mu.Lock() defer em.mu.Unlock() // 获取要合并的文件列表 filesToMerge, err := em.getFilesToMerge(config) if err != nil { return err } fmt.Printf("开始按列合并 %d 个文件:\n", len(filesToMerge)) // 创建新的输出文件 outputFile := excelize.NewFile() defer outputFile.Close() // 删除默认的Sheet1 outputFile.DeleteSheet("Sheet1") // 创建目标sheet sheetIndex, err := outputFile.NewSheet(config.SheetName) if err != nil { return fmt.Errorf("创建sheet失败: %v", err) } outputFile.SetActiveSheet(sheetIndex) currentCol := 1 // 合并所有文件 for fileIndex, sourceFile := range filesToMerge { fmt.Printf("[%d/%d] 正在处理文件: %s\n", fileIndex+1, len(filesToMerge), filepath.Base(sourceFile)) // 打开源文件 srcFile, err := excelize.OpenFile(sourceFile) if err != nil { return fmt.Errorf("打开文件 %s 失败: %v", sourceFile, err) } defer srcFile.Close() // 确定要读取的sheet sourceSheet := em.getSourceSheet(srcFile, config.SourceSheet) if sourceSheet == "" { return fmt.Errorf("未找到可用的sheet") } // 读取源文件数据 rows, err := srcFile.GetRows(sourceSheet) if err != nil { return fmt.Errorf("读取文件 %s 失败: %v,跳过\n", sourceFile, err) } if len(rows) == 0 { fmt.Printf("警告: 文件 %s 的sheet '%s' 没有数据,跳过\n", sourceFile, sourceSheet) continue } // 按列写入数据 for rowIndex, row := range rows { // 写入当前列的所有行 for colIndex, cell := range row { targetRow := rowIndex + 1 cellName, _ := excelize.CoordinatesToCellName(currentCol+colIndex, targetRow) outputFile.SetCellValue(config.SheetName, cellName, cell) } } // 添加文件名称到第一行(作为列标题) titleCell, _ := excelize.CoordinatesToCellName(currentCol, 1) outputFile.SetCellValue(config.SheetName, titleCell, filepath.Base(sourceFile)) // 移动到下一组列 if len(rows) > 0 && len(rows[0]) > 0 { currentCol += len(rows[0]) } else { currentCol += 1 } } // 保存输出文件 if err := outputFile.SaveAs(config.OutputFile); err != nil { return fmt.Errorf("保存合并文件失败: %v", err) } fmt.Printf("按列合并完成!结果保存在: %s\n", config.OutputFile) return nil } // MergeSheetsInSameFile 合并同一文件中的多个sheet func (em *ExcelManager) MergeSheetsInSameFile(filename, outputFile string, targetSheetName string) error { em.mu.RLock() defer em.mu.RUnlock() file, err := excelize.OpenFile(filename) if err != nil { return err } defer file.Close() // 获取所有sheet sheets := file.GetSheetList() if len(sheets) == 0 { return fmt.Errorf("文件 %s 中没有sheet", filename) } // 创建新的输出文件 output := excelize.NewFile() defer output.Close() // 删除默认的Sheet1 output.DeleteSheet("Sheet1") // 创建目标sheet sheetIndex, err := output.NewSheet(targetSheetName) if err != nil { return fmt.Errorf("创建sheet失败: %v", err) } output.SetActiveSheet(sheetIndex) currentRow := 1 for _, sheet := range sheets { // 读取sheet数据 rows, err := file.GetRows(sheet) if err != nil { fmt.Printf("警告: 读取sheet %s 失败: %v,跳过\n", sheet, err) continue } if len(rows) == 0 { continue } // 添加sheet名称作为标题 titleCell, _ := excelize.CoordinatesToCellName(1, currentRow) output.SetCellValue(targetSheetName, titleCell, fmt.Sprintf("=== Sheet: %s ===", sheet)) currentRow++ // 写入sheet数据 for _, row := range rows { for colIndex, cell := range row { cellName, _ := excelize.CoordinatesToCellName(colIndex+1, currentRow) output.SetCellValue(targetSheetName, cellName, cell) } currentRow++ } // 添加空行分隔 currentRow++ } // 保存输出文件 return output.SaveAs(outputFile) } // ============ 辅助结构和方法 ============ // 文件任务结构 type fileTask struct { filename string index int total int } // 文件结果结构 type fileResult struct { filename string index int data fileData } // 文件数据结构 type fileData struct { rows [][]string err error } // 并行读取Excel文件 func (em *ExcelManager) readExcelFileParallel(filename, sheetName string) fileData { srcFile, err := excelize.OpenFile(filename) if err != nil { return fileData{err: err} } defer srcFile.Close() sourceSheet := em.getSourceSheet(srcFile, sheetName) if sourceSheet == "" { return fileData{err: fmt.Errorf("未找到可用的sheet")} } rows, err := srcFile.GetRows(sourceSheet) return fileData{ rows: rows, err: err, } } // 检查行是否为空 func (em *ExcelManager) isRowEmpty(row []string) bool { for _, cell := range row { if strings.TrimSpace(cell) != "" { return false } } return true } // 清理测试文件 func cleanupFiles(file string) { if _, err := os.Stat(file); err == nil { os.Remove(file) fmt.Printf("删除: %s\n", file) } } // 辅助函数:将数据转换为JSON字符串 func convertToJSON(data interface{}) string { // 这里使用简单的转换,实际可以使用 encoding/json 包 switch v := data.(type) { case [][]string: return convertRowsToJSON(v) case []string: return strings.Join(v, "\n") default: return fmt.Sprintf("%v", data) } } // 将行数据转换为 JSON 字符串 func convertRowsToJSON(rows [][]string) string { if len(rows) == 0 { return "[]" } // 如果有表头,将数据转换为对象数组 if len(rows) > 1 { headers := rows[0] var result []map[string]string // 从第二行开始(跳过表头) for i := 1; i < len(rows); i++ { rowData := make(map[string]string) for j := 0; j < len(headers) && j < len(rows[i]); j++ { rowData[headers[j]] = rows[i][j] } result = append(result, rowData) } jsonBytes, err := json.Marshal(result) if err != nil { // 如果序列化失败,返回简单格式 return fmt.Sprintf("%v", rows) } return string(jsonBytes) } // 如果没有表头,返回二维数组 jsonBytes, err := json.Marshal(rows) if err != nil { return fmt.Sprintf("%v", rows) } return string(jsonBytes) } // 将C字符串数组转换为Go字符串切片 func cStringArrayToStringSlice(cArray **C.char, length int) []string { if cArray == nil || length == 0 { return nil } var goStrs []string for i := 0; i < length; i++ { ptr := (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(cArray)) + uintptr(i)*unsafe.Sizeof(uintptr(0)))) if *ptr != nil { goStrs = append(goStrs, C.GoString(*ptr)) } } return goStrs } // 辅助函数:设置错误信息 func setError(err string) { // 这里可以添加日志记录等操作 fmt.Printf("Excel操作错误: %s\n", err) } // ============ CGO 导出函数 ============ var ( managerStore sync.Map nextHandle int64 = 1 ) // 创建新的Excel管理器并返回指针 // //export NewExcelManagerInstance func NewExcelManagerInstance() C.longlong { manager := NewExcelManager() handle := nextHandle nextHandle++ // 将Go对象存储在map中 managerStore.Store(handle, manager) return C.longlong(handle) } // 释放Excel管理器 // //export FreeExcelManager func FreeExcelManager(handle C.longlong) { h := int64(handle) // 从map中删除并清理 if mgr, ok := managerStore.Load(h); ok { if manager, ok := mgr.(*ExcelManager); ok { manager.CloseAll() } managerStore.Delete(h) } } // 读取Excel数据 // //export ReadExcelData func ReadExcelData(handle C.longlong, filename *C.char, sheet *C.char, result **C.char) C.int { h := int64(handle) mgr, ok := managerStore.Load(h) if !ok { return C.int(-1) } manager, ok := mgr.(*ExcelManager) if !ok { return C.int(-1) } goFilename := C.GoString(filename) goSheet := C.GoString(sheet) data, err := manager.ReadData(goFilename, goSheet) if err != nil { return C.int(-1) } jsonStr := convertRowsToJSON(data) // 将数据转换为JSON字符串 //jsonStr := convertToJSON(data) //// 将结果转换为JSON格式 //jsonData, err := ParseExcelDataToJSON(jsonStr) //var datas string //if err != nil { // fmt.Printf("转换JSON失败: %v\n", err) //} else { // // 将JSON数据格式化输出 // jsonBytes, err := json.Marshal(jsonData) // if err != nil { // fmt.Printf("格式化JSON失败: %v\n", err) // } else { // datas = string(jsonBytes) // } //} *result = C.CString(jsonStr) return C.int(0) } func ParseExcelDataToJSON(excelData string) ([]map[string]string, error) { if excelData == "" { return nil, fmt.Errorf("Excel数据为空") } // 使用csv解析器解析数据 reader := csv.NewReader(strings.NewReader(excelData)) records, err := reader.ReadAll() if err != nil { return nil, fmt.Errorf("解析Excel数据失败: %v", err) } if len(records) < 2 { return nil, fmt.Errorf("数据行数不足") } // 提取表头(第一行) headers := records[0] // 将数据转换为JSON格式 var jsonData []map[string]string // 从第二行开始(跳过表头) for i := 1; i < len(records); i++ { row := records[i] rowData := make(map[string]string) // 确保每行的列数与表头一致 for j := 0; j < len(headers) && j < len(row); j++ { rowData[headers[j]] = row[j] } jsonData = append(jsonData, rowData) } return jsonData, nil } // 批量写入数据到Excel文件 // //export WriteBatchData func WriteBatchData(handle C.longlong, filename *C.char, sheet *C.char, cells *C.char, values *C.char, count C.int) C.int { h := int64(handle) mgr, ok := managerStore.Load(h) if !ok { return C.int(-1) } manager, ok := mgr.(*ExcelManager) if !ok { return C.int(-1) } goFilename := C.GoString(filename) goSheet := C.GoString(sheet) goCells := C.GoString(cells) goValues := C.GoString(values) var cell []string var value []string err := json.Unmarshal([]byte(goCells), &cell) if err != nil { setError(fmt.Sprintf("解析数据失败: %v,数据: %s", err, goCells)) return C.int(-1) } err = json.Unmarshal([]byte(goValues), &value) if err != nil { setError(fmt.Sprintf("解析数据失败: %v,数据: %s", err, goValues)) return C.int(-1) } // 构建数据映射 data := make(map[string]interface{}) for i, c := range cell { data[c] = value[i] } err = manager.WriteData(goFilename, goSheet, data) if err != nil { fmt.Printf("批量写入数据失败: %v\n", err) return C.int(-1) } return C.int(0) } // 追加数据到Excel文件末尾 // //export AppendDataToExcel func AppendDataToExcel(handle C.longlong, filename *C.char, sheet *C.char, values *C.char, count C.int) C.int { h := int64(handle) mgr, ok := managerStore.Load(h) if !ok { return C.int(-1) } manager, ok := mgr.(*ExcelManager) if !ok { return C.int(-1) } goFilename := C.GoString(filename) goSheet := C.GoString(sheet) goValues := C.GoString(values) var value []string err := json.Unmarshal([]byte(goValues), &value) if err != nil { setError(fmt.Sprintf("解析数据失败: %v,数据: %s", err, goValues)) return C.int(-1) } // 转换为interface{}切片 var rowData []interface{} for _, val := range value { rowData = append(rowData, val) } err = manager.AppendData(goFilename, goSheet, rowData) if err != nil { fmt.Printf("追加数据失败: %v\n", err) return C.int(-1) } return C.int(0) } // 搜索包含关键字的单元格 // //export SearchByKeyword func SearchByKeyword(handle C.longlong, filename *C.char, sheet *C.char, keyword *C.char, result **C.char) C.int { h := int64(handle) mgr, ok := managerStore.Load(h) if !ok { return C.int(-1) } manager, ok := mgr.(*ExcelManager) if !ok { return C.int(-1) } goFilename := C.GoString(filename) goSheet := C.GoString(sheet) goKeyword := C.GoString(keyword) results, err := manager.SearchByKeyword(goFilename, goSheet, goKeyword) if err != nil { return C.int(-1) } // 将结果转换为JSON字符串 jsonStr := convertToJSON(results) *result = C.CString(jsonStr) return C.int(0) } // 搜索整行包含关键字的行 // //export SearchRowsByKeyword func SearchRowsByKeyword(handle C.longlong, filename *C.char, sheet *C.char, keyword *C.char, result **C.char) C.int { h := int64(handle) mgr, ok := managerStore.Load(h) if !ok { return C.int(-1) } manager, ok := mgr.(*ExcelManager) if !ok { return C.int(-1) } goFilename := C.GoString(filename) goSheet := C.GoString(sheet) goKeyword := C.GoString(keyword) results, err := manager.SearchRowData(goFilename, goSheet, goKeyword) if err != nil { return C.int(-1) } // 将结果转换为JSON字符串 jsonStr := convertToJSON(results) *result = C.CString(jsonStr) return C.int(0) } // 创建新文件并写入数据 // //export CreateAndWriteExcel func CreateAndWriteExcel(handle C.longlong, filename *C.char, sheet *C.char, rowsData *C.char) C.int { h := int64(handle) fmt.Println("managerStore:", managerStore) // 获取管理器 mgr, ok := managerStore.Load(h) if !ok { setError("Invalid handle") return C.int(-1) } manager, ok := mgr.(*ExcelManager) if !ok { setError("Invalid manager type") return C.int(-1) } goFilename := C.GoString(filename) goSheet := C.GoString(sheet) goRowsData := C.GoString(rowsData) var data [][]string err2 := json.Unmarshal([]byte(goRowsData), &data) if err2 != nil { // 更详细的错误信息 setError(fmt.Sprintf("解析数据失败: %v, 数据: %s", err2, goRowsData)) return C.int(-1) } // 调用管理器方法 err := manager.CreateAndWrite(goFilename, goSheet, data) if err != nil { setError(fmt.Sprintf("创建并写入文件失败: %v", err)) return C.int(-1) } fmt.Printf("文件创建成功: %s\n", goFilename) return C.int(0) } // 增强版合并Excel文件(支持指定文件列表) // //export MergeExcelFilesEx func MergeExcelFilesEx(handle C.longlong, sourceDir *C.char, specificFiles *C.char, outputFile *C.char, sheetName *C.char, mergeByColumn C.int, includeHeaders C.int, skipEmptyRows C.int, filePattern *C.char, sourceSheet *C.char, addSourceColumn C.int, addIndexColumn C.int) C.int { h := int64(handle) mgr, ok := managerStore.Load(h) if !ok { return C.int(-1) } manager, ok := mgr.(*ExcelManager) if !ok { return C.int(-1) } goSpecificFiles := C.GoString(specificFiles) var data []string err2 := json.Unmarshal([]byte(goSpecificFiles), &data) if err2 != nil { // 更详细的错误信息 setError(fmt.Sprintf("解析数据失败: %v, 数据: %s", err2, goSpecificFiles)) return C.int(-1) } // 构建配置 config := MergeConfig{ SourceDir: C.GoString(sourceDir), SpecificFiles: data, OutputFile: C.GoString(outputFile), SheetName: C.GoString(sheetName), MergeByColumn: mergeByColumn != 0, IncludeHeaders: includeHeaders != 0, SkipEmptyRows: skipEmptyRows != 0, FilePattern: C.GoString(filePattern), AddSourceColumn: addSourceColumn != 0, AddIndexColumn: addIndexColumn != 0, SourceSheet: C.GoString(sourceSheet), } // 根据合并模式调用不同的方法 var err error if config.MergeByColumn { err = manager.MergeByColumn(config) } else { err = manager.MergeExcelFiles(config) } if err != nil { fmt.Printf("合并Excel文件失败: %v\n", err) return C.int(-1) } return C.int(0) } // 并行合并Excel文件(增强版) // //export MergeExcelFilesParallelEx func MergeExcelFilesParallelEx(handle C.longlong, sourceDir *C.char, specificFiles **C.char, fileCount C.int, outputFile *C.char, sheetName *C.char, includeHeaders C.int, skipEmptyRows C.int, filePattern *C.char, sourceSheet *C.char, addSourceColumn C.int, addIndexColumn C.int, workers C.int) C.int { h := int64(handle) mgr, ok := managerStore.Load(h) if !ok { return C.int(-1) } manager, ok := mgr.(*ExcelManager) if !ok { return C.int(-1) } // 构建配置 config := MergeConfig{ SourceDir: C.GoString(sourceDir), OutputFile: C.GoString(outputFile), SheetName: C.GoString(sheetName), IncludeHeaders: includeHeaders != 0, SkipEmptyRows: skipEmptyRows != 0, FilePattern: C.GoString(filePattern), AddSourceColumn: addSourceColumn != 0, AddIndexColumn: addIndexColumn != 0, SourceSheet: C.GoString(sourceSheet), } // 如果有指定的文件列表,则添加到配置中 if fileCount > 0 && specificFiles != nil { config.SpecificFiles = cStringArrayToStringSlice(specificFiles, int(fileCount)) } err := manager.MergeExcelFilesParallel(config, int(workers)) if err != nil { fmt.Printf("并行合并Excel文件失败: %v\n", err) return C.int(-1) } return C.int(0) } // 合并同一文件中的多个sheet // //export MergeSheetsInFile func MergeSheetsInFile(handle C.longlong, filename *C.char, outputFile *C.char, targetSheetName *C.char) C.int { h := int64(handle) mgr, ok := managerStore.Load(h) if !ok { return C.int(-1) } manager, ok := mgr.(*ExcelManager) if !ok { return C.int(-1) } goFilename := C.GoString(filename) goOutputFile := C.GoString(outputFile) goTargetSheet := C.GoString(targetSheetName) err := manager.MergeSheetsInSameFile(goFilename, goOutputFile, goTargetSheet) if err != nil { fmt.Printf("合并sheet失败: %v\n", err) return C.int(-1) } return C.int(0) } // 释放C字符串 // //export FreeCString func FreeCString(str *C.char) { if str != nil { C.free(unsafe.Pointer(str)) } } //func main() { // //}