using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Excel = Microsoft.Office.Interop.Excel;
namespace TableMagic.Skills
{
public class ExcelFileSkill : ISkill
{
public string Name => "ExcelFile";
public string Description => "文件/文件夹技能,支持批量重命名、复制、移动、删除等文件操作";
public List<SkillTool> GetTools()
{
return new List<SkillTool>
{
new SkillTool
{
Name = "list_files",
Description = "列出文件夹中的文件信息。当用户要求查看文件列表、列出文件时使用此工具。",
Parameters = new Dictionary<string, object>
{
{ "type", "object" },
{ "properties", new Dictionary<string, object>
{
{ "folderPath", new { type = "string", description = "文件夹路径" } },
{ "pattern", new { type = "string", description = "文件筛选模式(如*.xlsx,可选)" } },
{ "includeSubfolders", new { type = "boolean", description = "是否包含子目录(默认false)" } },
{ "outputSheetName", new { type = "string", description = "输出工作表名称(可选)" } }
}
}
},
RequiredParameters = new List<string> { "folderPath" }
},
new SkillTool
{
Name = "batch_rename",
Description = "根据Excel数据批量重命名文件。Excel中需包含原文件名和新文件名列。当用户要求批量重命名文件时使用此工具。",
Parameters = new Dictionary<string, object>
{
{ "type", "object" },
{ "properties", new Dictionary<string, object>
{
{ "oldNameColumn", new { type = "string", description = "原文件名列名" } },
{ "newNameColumn", new { type = "string", description = "新文件名列名" } },
{ "folderPath", new { type = "string", description = "文件所在文件夹路径(可选,不填则使用完整路径)" } },
{ "sheetName", new { type = "string", description = "工作表名称(可选)" } }
}
}
},
RequiredParameters = new List<string> { "oldNameColumn", "newNameColumn" }
},
new SkillTool
{
Name = "batch_copy",
Description = "批量复制文件到目标文件夹。当用户要求批量复制文件时使用此工具。",
Parameters = new Dictionary<string, object>
{
{ "type", "object" },
{ "properties", new Dictionary<string, object>
{
{ "fileNameColumn", new { type = "string", description = "文件名/路径列名" } },
{ "targetFolder", new { type = "string", description = "目标文件夹路径" } },
{ "sourceFolder", new { type = "string", description = "源文件夹路径(可选,不填则使用完整路径)" } },
{ "sheetName", new { type = "string", description = "工作表名称(可选)" } }
}
}
},
RequiredParameters = new List<string> { "fileNameColumn", "targetFolder" }
},
new SkillTool
{
Name = "batch_move",
Description = "批量移动文件到目标文件夹。当用户要求批量移动文件时使用此工具。",
Parameters = new Dictionary<string, object>
{
{ "type", "object" },
{ "properties", new Dictionary<string, object>
{
{ "fileNameColumn", new { type = "string", description = "文件名/路径列名" } },
{ "targetFolder", new { type = "string", description = "目标文件夹路径" } },
{ "sourceFolder", new { type = "string", description = "源文件夹路径(可选)" } },
{ "sheetName", new { type = "string", description = "工作表名称(可选)" } }
}
}
},
RequiredParameters = new List<string> { "fileNameColumn", "targetFolder" }
},
new SkillTool
{
Name = "batch_delete",
Description = "批量删除文件。当用户要求批量删除文件时使用此工具。",
Parameters = new Dictionary<string, object>
{
{ "type", "object" },
{ "properties", new Dictionary<string, object>
{
{ "fileNameColumn", new { type = "string", description = "文件名/路径列名" } },
{ "folderPath", new { type = "string", description = "文件所在文件夹路径(可选)" } },
{ "sheetName", new { type = "string", description = "工作表名称(可选)" } }
}
}
},
RequiredParameters = new List<string> { "fileNameColumn" }
},
new SkillTool
{
Name = "create_folder",
Description = "创建文件夹。当用户要求创建文件夹、新建目录时使用此工具。",
Parameters = new Dictionary<string, object>
{
{ "type", "object" },
{ "properties", new Dictionary<string, object>
{
{ "folderPath", new { type = "string", description = "文件夹路径" } }
}
}
},
RequiredParameters = new List<string> { "folderPath" }
},
new SkillTool
{
Name = "get_file_info",
Description = "获取文件详细信息(大小、创建时间、修改时间等)。",
Parameters = new Dictionary<string, object>
{
{ "type", "object" },
{ "properties", new Dictionary<string, object>
{
{ "filePath", new { type = "string", description = "文件路径" } }
}
}
},
RequiredParameters = new List<string> { "filePath" }
},
new SkillTool
{
Name = "open_folder",
Description = "在资源管理器中打开文件夹。",
Parameters = new Dictionary<string, object>
{
{ "type", "object" },
{ "properties", new Dictionary<string, object>
{
{ "folderPath", new { type = "string", description = "文件夹路径" } }
}
}
},
RequiredParameters = new List<string> { "folderPath" }
}
};
}
public async Task<SkillResult> ExecuteToolAsync(string toolName, Dictionary<string, object> arguments)
{
try
{
switch (toolName)
{
case "list_files":
return await ListFilesAsync(arguments);
case "batch_rename":
return await BatchRenameAsync(arguments);
case "batch_copy":
return await BatchCopyAsync(arguments);
case "batch_move":
return await BatchMoveAsync(arguments);
case "batch_delete":
return await BatchDeleteAsync(arguments);
case "create_folder":
return CreateFolder(arguments);
case "get_file_info":
return GetFileInfo(arguments);
case "open_folder":
return OpenFolder(arguments);
default:
return new SkillResult { Success = false, Error = $"Tool {toolName} not implemented in ExcelFileSkill" };
}
}
catch (Exception ex)
{
return new SkillResult { Success = false, Error = ex.Message };
}
}
private async Task<SkillResult> ListFilesAsync(Dictionary<string, object> arguments)
{
return await Task.Run(() =>
{
var folderPath = arguments["folderPath"].ToString();
var pattern = arguments.ContainsKey("pattern") ? arguments["pattern"].ToString() : "*.*";
var includeSubfolders = arguments.ContainsKey("includeSubfolders") && Convert.ToBoolean(arguments["includeSubfolders"]);
var outputSheetName = arguments.ContainsKey("outputSheetName")
? arguments["outputSheetName"].ToString()
: "文件列表";
if (!Directory.Exists(folderPath))
return new SkillResult { Success = false, Error = $"文件夹不存在: {folderPath}" };
var searchOption = includeSubfolders ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
var files = Directory.GetFiles(folderPath, pattern, searchOption);
var workbook = ThisAddIn.app.ActiveWorkbook;
ThisAddIn.app.ScreenUpdating = false;
ThisAddIn.app.DisplayAlerts = false;
Excel.Worksheet sheet;
var existingNames = new List<string>();
foreach (Excel.Worksheet ws in workbook.Worksheets) existingNames.Add(ws.Name);
string actualSheetName = outputSheetName;
if (existingNames.Any(n => string.Equals(n, outputSheetName, StringComparison.OrdinalIgnoreCase)))
{
int suffix = 2;
while (existingNames.Any(n => string.Equals(n, $"{outputSheetName}_{suffix}", StringComparison.OrdinalIgnoreCase)))
{
suffix++;
}
actualSheetName = $"{outputSheetName}_{suffix}";
}
sheet = workbook.Worksheets.Add(After: workbook.Worksheets[workbook.Worksheets.Count]);
sheet.Name = actualSheetName;
var headers = new[] { "文件名", "扩展名", "大小(KB)", "创建时间", "修改时间", "完整路径" };
for (int c = 0; c < headers.Length; c++)
{
sheet.Cells[1, c + 1].Value = headers[c];
sheet.Cells[1, c + 1].Font.Bold = true;
}
for (int i = 0; i < files.Length; i++)
{
var file = files[i];
var fileInfo = new FileInfo(file);
sheet.Cells[i + 2, 1].Value = fileInfo.Name;
sheet.Cells[i + 2, 2].Value = fileInfo.Extension;
sheet.Cells[i + 2, 3].Value = Math.Round(fileInfo.Length / 1024.0, 2);
sheet.Cells[i + 2, 4].Value = fileInfo.CreationTime.ToString("yyyy-MM-dd HH:mm:ss");
sheet.Cells[i + 2, 5].Value = fileInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss");
sheet.Cells[i + 2, 6].Value = file;
}
sheet.UsedRange.Columns.AutoFit();
sheet.Activate();
ThisAddIn.app.ScreenUpdating = true;
ThisAddIn.app.DisplayAlerts = true;
return new SkillResult { Success = true, Content = $"文件列表已导出,共 {files.Length} 个文件" };
});
}
private async Task<SkillResult> BatchRenameAsync(Dictionary<string, object> arguments)
{
return await Task.Run(() =>
{
var oldNameColumn = arguments["oldNameColumn"].ToString();
var newNameColumn = arguments["newNameColumn"].ToString();
var folderPath = arguments.ContainsKey("folderPath") ? arguments["folderPath"].ToString() : null;
var sheetName = arguments.ContainsKey("sheetName") ? arguments["sheetName"].ToString() : null;
var workbook = ThisAddIn.app.ActiveWorkbook;
var sheet = string.IsNullOrEmpty(sheetName) ? workbook.ActiveSheet : workbook.Worksheets[sheetName];
var usedRange = sheet.UsedRange;
int lastRow = usedRange.Rows.Count;
int lastCol = usedRange.Columns.Count;
var columnMap = new Dictionary<string, int>();
for (int c = 1; c <= lastCol; c++)
{
var colName = sheet.Cells[1, c].Text?.ToString();
if (!string.IsNullOrEmpty(colName))
columnMap[colName] = c;
}
if (!columnMap.ContainsKey(oldNameColumn) || !columnMap.ContainsKey(newNameColumn))
return new SkillResult { Success = false, Error = "未找到指定的列" };
int oldColIdx = columnMap[oldNameColumn];
int newColIdx = columnMap[newNameColumn];
int successCount = 0;
int failCount = 0;
var errors = new List<string>();
for (int r = 2; r <= lastRow; r++)
{
var oldName = sheet.Cells[r, oldColIdx].Text?.ToString();
var newName = sheet.Cells[r, newColIdx].Text?.ToString();
if (string.IsNullOrEmpty(oldName) || string.IsNullOrEmpty(newName)) continue;
string oldPath, newPath;
if (!string.IsNullOrEmpty(folderPath))
{
oldPath = Path.Combine(folderPath, oldName);
newPath = Path.Combine(folderPath, newName);
}
else
{
oldPath = oldName;
newPath = newName;
}
try
{
if (File.Exists(oldPath))
{
File.Move(oldPath, newPath);
successCount++;
}
else if (Directory.Exists(oldPath))
{
Directory.Move(oldPath, newPath);
successCount++;
}
else
{
failCount++;
errors.Add($"行{r}: 文件不存在 {oldPath}");
}
}
catch (Exception ex)
{
failCount++;
errors.Add($"行{r}: {ex.Message}");
}
}
var result = $"批量重命名完成\n成功: {successCount} 个\n失败: {failCount} 个";
if (errors.Count > 0)
result += $"\n失败详情:\n{string.Join("\n", errors.Take(10))}";
return new SkillResult { Success = failCount == 0, Content = result };
});
}
private async Task<SkillResult> BatchCopyAsync(Dictionary<string, object> arguments)
{
return await Task.Run(() =>
{
var fileNameColumn = arguments["fileNameColumn"].ToString();
var targetFolder = arguments["targetFolder"].ToString();
var sourceFolder = arguments.ContainsKey("sourceFolder") ? arguments["sourceFolder"].ToString() : null;
var sheetName = arguments.ContainsKey("sheetName") ? arguments["sheetName"].ToString() : null;
if (!Directory.Exists(targetFolder))
Directory.CreateDirectory(targetFolder);
var workbook = ThisAddIn.app.ActiveWorkbook;
var sheet = string.IsNullOrEmpty(sheetName) ? workbook.ActiveSheet : workbook.Worksheets[sheetName];
var usedRange = sheet.UsedRange;
int lastRow = usedRange.Rows.Count;
int lastCol = usedRange.Columns.Count;
var columnMap = new Dictionary<string, int>();
for (int c = 1; c <= lastCol; c++)
{
var colName = sheet.Cells[1, c].Text?.ToString();
if (!string.IsNullOrEmpty(colName))
columnMap[colName] = c;
}
if (!columnMap.ContainsKey(fileNameColumn))
return new SkillResult { Success = false, Error = $"未找到列: {fileNameColumn}" };
int fileColIdx = columnMap[fileNameColumn];
int successCount = 0;
int failCount = 0;
for (int r = 2; r <= lastRow; r++)
{
var fileName = sheet.Cells[r, fileColIdx].Text?.ToString();
if (string.IsNullOrEmpty(fileName)) continue;
string sourcePath = !string.IsNullOrEmpty(sourceFolder)
? Path.Combine(sourceFolder, fileName)
: fileName;
var targetPath = Path.Combine(targetFolder, Path.GetFileName(fileName));
try
{
if (File.Exists(sourcePath))
{
File.Copy(sourcePath, targetPath, true);
successCount++;
}
else
{
failCount++;
}
}
catch
{
failCount++;
}
}
return new SkillResult { Success = true, Content = $"批量复制完成\n成功: {successCount} 个\n失败: {failCount} 个" };
});
}
private async Task<SkillResult> BatchMoveAsync(Dictionary<string, object> arguments)
{
return await Task.Run(() =>
{
var fileNameColumn = arguments["fileNameColumn"].ToString();
var targetFolder = arguments["targetFolder"].ToString();
var sourceFolder = arguments.ContainsKey("sourceFolder") ? arguments["sourceFolder"].ToString() : null;
var sheetName = arguments.ContainsKey("sheetName") ? arguments["sheetName"].ToString() : null;
if (!Directory.Exists(targetFolder))
Directory.CreateDirectory(targetFolder);
var workbook = ThisAddIn.app.ActiveWorkbook;
var sheet = string.IsNullOrEmpty(sheetName) ? workbook.ActiveSheet : workbook.Worksheets[sheetName];
var usedRange = sheet.UsedRange;
int lastRow = usedRange.Rows.Count;
int lastCol = usedRange.Columns.Count;
var columnMap = new Dictionary<string, int>();
for (int c = 1; c <= lastCol; c++)
{
var colName = sheet.Cells[1, c].Text?.ToString();
if (!string.IsNullOrEmpty(colName))
columnMap[colName] = c;
}
if (!columnMap.ContainsKey(fileNameColumn))
return new SkillResult { Success = false, Error = $"未找到列: {fileNameColumn}" };
int fileColIdx = columnMap[fileNameColumn];
int successCount = 0;
int failCount = 0;
for (int r = 2; r <= lastRow; r++)
{
var fileName = sheet.Cells[r, fileColIdx].Text?.ToString();
if (string.IsNullOrEmpty(fileName)) continue;
string sourcePath = !string.IsNullOrEmpty(sourceFolder)
? Path.Combine(sourceFolder, fileName)
: fileName;
var targetPath = Path.Combine(targetFolder, Path.GetFileName(fileName));
try
{
if (File.Exists(sourcePath))
{
File.Move(sourcePath, targetPath);
successCount++;
}
else
{
failCount++;
}
}
catch
{
failCount++;
}
}
return new SkillResult { Success = true, Content = $"批量移动完成\n成功: {successCount} 个\n失败: {failCount} 个" };
});
}
private async Task<SkillResult> BatchDeleteAsync(Dictionary<string, object> arguments)
{
return await Task.Run(() =>
{
var fileNameColumn = arguments["fileNameColumn"].ToString();
var folderPath = arguments.ContainsKey("folderPath") ? arguments["folderPath"].ToString() : null;
var sheetName = arguments.ContainsKey("sheetName") ? arguments["sheetName"].ToString() : null;
var workbook = ThisAddIn.app.ActiveWorkbook;
var sheet = string.IsNullOrEmpty(sheetName) ? workbook.ActiveSheet : workbook.Worksheets[sheetName];
var usedRange = sheet.UsedRange;
int lastRow = usedRange.Rows.Count;
int lastCol = usedRange.Columns.Count;
var columnMap = new Dictionary<string, int>();
for (int c = 1; c <= lastCol; c++)
{
var colName = sheet.Cells[1, c].Text?.ToString();
if (!string.IsNullOrEmpty(colName))
columnMap[colName] = c;
}
if (!columnMap.ContainsKey(fileNameColumn))
return new SkillResult { Success = false, Error = $"未找到列: {fileNameColumn}" };
int fileColIdx = columnMap[fileNameColumn];
int successCount = 0;
int failCount = 0;
for (int r = 2; r <= lastRow; r++)
{
var fileName = sheet.Cells[r, fileColIdx].Text?.ToString();
if (string.IsNullOrEmpty(fileName)) continue;
string filePath = !string.IsNullOrEmpty(folderPath)
? Path.Combine(folderPath, fileName)
: fileName;
try
{
if (File.Exists(filePath))
{
File.Delete(filePath);
successCount++;
}
else
{
failCount++;
}
}
catch
{
failCount++;
}
}
return new SkillResult { Success = true, Content = $"批量删除完成\n成功: {successCount} 个\n失败: {failCount} 个" };
});
}
private SkillResult CreateFolder(Dictionary<string, object> arguments)
{
var folderPath = arguments["folderPath"].ToString();
try
{
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
return new SkillResult { Success = true, Content = $"文件夹创建成功: {folderPath}" };
}
else
{
return new SkillResult { Success = true, Content = $"文件夹已存在: {folderPath}" };
}
}
catch (Exception ex)
{
return new SkillResult { Success = false, Error = $"创建文件夹失败: {ex.Message}" };
}
}
private SkillResult GetFileInfo(Dictionary<string, object> arguments)
{
var filePath = arguments["filePath"].ToString();
if (!File.Exists(filePath))
return new SkillResult { Success = false, Error = $"文件不存在: {filePath}" };
var fileInfo = new FileInfo(filePath);
return new SkillResult
{
Success = true,
Content = $"文件信息:\n名称: {fileInfo.Name}\n大小: {fileInfo.Length / 1024.0:F2} KB\n创建时间: {fileInfo.CreationTime}\n修改时间: {fileInfo.LastWriteTime}\n路径: {fileInfo.FullName}"
};
}
private SkillResult OpenFolder(Dictionary<string, object> arguments)
{
var folderPath = arguments["folderPath"].ToString();
if (!Directory.Exists(folderPath))
return new SkillResult { Success = false, Error = $"文件夹不存在: {folderPath}" };
try
{
System.Diagnostics.Process.Start("explorer.exe", folderPath);
return new SkillResult { Success = true, Content = $"已打开文件夹: {folderPath}" };
}
catch (Exception ex)
{
return new SkillResult { Success = false, Error = $"打开文件夹失败: {ex.Message}" };
}
}
}
}