refactor: 优化 Excel 解析流程与代码生成健壮性

- 新增 ParsedSheet 类统一承载单个 sheet 的解析结果(SheetName / Headers / Data)
- ExcelHelper 新增 ParseAllSheets(),一次打开文件完成所有 sheet 解析,
  消除原先 ExcelHeaders + ExcelData 重复打开同一文件的问题
- Program.cs 在遍历层面调用 ParseAllSheets(),解析结果共享给
  GenCSharpModel 和 ExportToFile,每个 xlsx 文件只打开一次
- GenModels / TableExcelExportBytes 签名改为接收 List<ParsedSheet>
- 修复 Program.cs 中遍历 excels 时 return 应为 continue 的 bug,
  避免遇到 ~$ 临时文件时提前退出
- TypeDescriptor 新增 ReadExpression 属性,GetReadExpr 改为直接读取该属性,
  消除原先通过字符串截取反推读取表达式的脆弱实现
- FileManager.WriteToFile 默认编码由 Encoding.Default 改为 UTF8(无 BOM),
  确保生成的 .cs 文件跨平台编码一致
- 移除 FileManager.CreateDir 中无条件删除已存在目录的危险逻辑
- 移除 CsvHelper 中未被调用的 CSVHeader / GenBinaryData 死代码,
  StreamReader / FileStream 改为 using 简写形式
- 清理 Program.cs 末尾遗留的注释测试代码和无效语句,补充 TODO 标记
This commit is contained in:
2026-03-25 19:11:06 +08:00
parent 4a02f69f29
commit 671b6fd440
7 changed files with 100 additions and 408 deletions
-235
View File
@@ -1,235 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Data;
using Spire.Xls;
namespace ExcelTool
{
public class CsvHelper
{
static DataTable CSVHeader(string fileName)
{
try
{
DataTable dt = new DataTable();
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs, Encoding.Default);
string strLine = "";
string[] aryLine;
int columnCount = 0;
int lineIndex = 0;
while ((strLine = sr.ReadLine()) != null)
{
aryLine = strLine.Replace("\"", "").Replace(" ", "").Split(',');
if (lineIndex == 0)
{
columnCount = aryLine.Length;
for (int i = 0; i < columnCount; i++)
{
int typeIndex = i * 2;
int nameIndex = typeIndex + 1;
if (nameIndex < columnCount)
{
DataColumn dc = new DataColumn($"{aryLine[nameIndex]}|{aryLine[typeIndex]}");
try
{
dt.Columns.Add(dc);
}
catch (Exception ex)
{
ConsoleHelper.WriteErrorLine(ex.ToString());
return null;
}
}
}
}
break;
}
sr.Close();
fs.Close();
sr.Dispose();
fs.Dispose();
return dt;
}
catch (Exception ex)
{
ConsoleHelper.WriteErrorLine(ex.ToString());
return null;
}
}
public static DataTable CSV2DataTable(string fileName)
{
try
{
DataTable dt = new DataTable();
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs, Encoding.Default);
string strLine = "";
string[] aryLine;
int columnCount = 0;
int lineIndex = 0;
while ((strLine = sr.ReadLine()) != null)
{
aryLine = strLine.Replace("\"", "").Replace(" ", "").Split(',');
if (lineIndex == 0)
{
columnCount = aryLine.Length;
for (int i = 0; i < columnCount; i++)
{
int typeIndex = i * 2;
int nameIndex = typeIndex + 1;
if (nameIndex < columnCount)
{
DataColumn dc = new DataColumn($"{aryLine[nameIndex]}|{aryLine[typeIndex]}");
try
{
dt.Columns.Add(dc);
}
catch (Exception ex)
{
ConsoleHelper.WriteErrorLine(ex.ToString());
return null;
}
}
}
columnCount /= 2;
}
else if (lineIndex == 1) // 注释行
{
// 注释行先不读,因为注释行里有,号无法分割
}
else
{
//1,gender1,12.8,TRUE,"[0,0,1]","[[0,0,0],[0,1,0],[0,2,0],[0,4,0]]"
List<string> strs = new List<string>();
StringBuilder sb = new StringBuilder();
bool flag = false;
for (int i = 0; i < strLine.Length; i++)
{
if (strLine[i] == '"')
{
flag = !flag;
}
else
{
if (flag || (!flag && strLine[i] != ','))
{
sb.Append(strLine[i]);
}
else
{
strs.Add(sb.ToString());
sb.Clear();
}
}
}
if (sb.Length > 0 || strs.Count < columnCount)
{
strs.Add(sb.ToString());
sb.Clear();
}
aryLine = strs.ToArray();
DataRow dr = dt.NewRow();
for (int j = 0; j < columnCount; j++)
{
dr[j] = aryLine[j];
}
dt.Rows.Add(dr);
}
lineIndex++;
}
sr.Close();
fs.Close();
sr.Dispose();
fs.Dispose();
return dt;
}
catch (Exception ex)
{
ConsoleHelper.WriteErrorLine(ex.ToString());
return null;
}
}
public static bool GenBinaryData(string fileName)
{
try
{
FileInfo fileInfo = new FileInfo(fileName);
var csvName = fileInfo.Name.Remove(fileInfo.Name.IndexOf(".csv"));
//先写入行数,然后没一行的数据一次写入 小写类型、字符串
List<Tuple<string, string>> datas = new List<Tuple<string, string>>();
var dataTable = CSV2DataTable(fileName);
Tuple<string, string> rowCount = new Tuple<string, string>("int", dataTable.Rows.Count.ToString());
datas.Add(rowCount);
//foreach (var col in dataTable.Columns)
//{
// ConsoleHelper.WriteInfoLine(col.ToString());
//}
//for (int i = 0; i < dataTable.Columns.Count; i++)
//{
// ConsoleHelper.WriteInfoLine(dataTable.Columns[i].ToString());
//}
foreach (DataRow row in dataTable.Rows)
{
for (int i = 0; i < dataTable.Columns.Count; i++)
{
var typeHeader = dataTable.Columns[i].ToString().ToLower();
var headers = typeHeader.Split('|');
Tuple<string, string> t = new Tuple<string, string>(headers[1], row[i].ToString());
datas.Add(t);
}
}
var binaryFilePath = Path.Combine(fileInfo.DirectoryName, $"{csvName}.bytes");
FileManager.WriteBinaryDatasToFile(binaryFilePath, datas);
return true;
}
catch (Exception ex)
{
ConsoleHelper.WriteErrorLine(ex.ToString());
return false;
}
}
public static string CsvToXlsx(string fileName)
{
try
{
FileInfo fileInfo = new FileInfo(fileName);
var filePath = fileInfo.DirectoryName;
var csvName = fileInfo.Name.Remove(fileInfo.Name.IndexOf(".csv"));
//加载CSV文件
Workbook workbook = new Workbook();
workbook.LoadFromFile(fileName, ",", 1, 1);
//获取第一个工作表
Worksheet sheet = workbook.Worksheets[0];
//访问工作表中使用的范围
CellRange usedRange = sheet.AllocatedRange;
//当将范围内的数字保存为文本时,忽略错误
usedRange.IgnoreErrorOptions = IgnoreErrorType.NumberAsText;
//自适应行高、列宽
usedRange.AutoFitColumns();
usedRange.AutoFitRows();
var excelPath = Path.Combine(filePath, $"{csvName}.xlsx");
//保存文档
workbook.SaveToFile(Path.Combine(filePath, $"{csvName}.xlsx"), ExcelVersion.Version2013);
return excelPath;
}
catch (Exception ex)
{
ConsoleHelper.WriteErrorLine(ex.ToString());
return null;
}
}
}
}
+55 -66
View File
@@ -9,46 +9,58 @@ namespace ExcelTool
{ {
public static class ExcelHelper public static class ExcelHelper
{ {
public static List<TableExcelHeader> ExcelHeaders(string fileName, out string sheetName, out int sheetCount, int sheetNum = 0) public static List<ParsedSheet> ParseAllSheets(string fileName)
{
List<ParsedSheet> result = [];
try
{
using FileStream fs = File.OpenRead(fileName);
XSSFWorkbook wk = new(fs);
int sheetCount = wk.NumberOfSheets;
for (int sheetNum = 0; sheetNum < sheetCount; sheetNum++)
{
ISheet sheet = wk.GetSheetAt(sheetNum);
string sheetName = sheet.SheetName;
// # 开头的 sheet 跳过
if (string.IsNullOrEmpty(sheetName) || sheetName.StartsWith('#'))
continue;
var parsed = ParseSheet(sheet, sheetName);
if (parsed != null)
result.Add(parsed);
}
}
catch (Exception ex)
{
ex.ToString().WriteErrorLine();
}
return result;
}
static ParsedSheet ParseSheet(ISheet sheet, string sheetName)
{ {
try try
{ {
List<TableExcelHeader> headers = []; IRow nameRow = sheet.GetRow(0);
IRow typeRow = sheet.GetRow(1);
using FileStream fs = File.OpenRead(fileName); IRow descRow = sheet.GetRow(2);
XSSFWorkbook wk = new(fs);
sheetCount = wk.NumberOfSheets;
if (sheetNum >= sheetCount)
{
sheetName = "";
return null;
}
ISheet sheet = wk.GetSheetAt(sheetNum);
sheetName = sheet.SheetName;
if (sheetName.StartsWith('#'))
{
return null;
}
IRow nameRow = sheet.GetRow(0); // 字段名
IRow typeRow = sheet.GetRow(1); // 类型
IRow descRow = sheet.GetRow(2); // 注释
var headers = new List<TableExcelHeader>();
for (int j = 0; j < nameRow.LastCellNum; j++) for (int j = 0; j < nameRow.LastCellNum; j++)
{ {
string fieldName = nameRow.GetCell(j)?.ToString() ?? ""; string fieldName = nameRow.GetCell(j)?.ToString() ?? "";
string fieldType = typeRow.GetCell(j)?.ToString() ?? ""; string fieldType = typeRow.GetCell(j)?.ToString() ?? "";
string fieldDesc = descRow.GetCell(j)?.ToString() ?? ""; string fieldDesc = descRow.GetCell(j)?.ToString() ?? "";
if (string.IsNullOrEmpty(fieldName)) if (string.IsNullOrEmpty(fieldName))
{ {
$"列 {j} 字段名为空".WriteErrorLine(); $"列 {j} 字段名为空".WriteErrorLine();
continue; continue;
} }
headers.Add(new TableExcelHeader() headers.Add(new TableExcelHeader
{ {
FieldName = fieldName, FieldName = fieldName,
FieldType = fieldType, FieldType = fieldType,
@@ -56,60 +68,34 @@ namespace ExcelTool
}); });
} }
return headers; // 数据从第 6 行开始(0-indexed
}
catch (Exception ex)
{
ex.ToString().WriteErrorLine();
sheetName = null;
sheetCount = 0;
return null;
}
}
public static TableExcelData ExcelData(string fileName, out string sheetName, out int sheetCount, int sheetNum = 0)
{
try
{
var excelHeader = ExcelHeaders(fileName, out sheetName, out sheetCount, sheetNum);
var tableRows = new List<TableExcelRow>(); var tableRows = new List<TableExcelRow>();
using FileStream fs = File.OpenRead(fileName);
IWorkbook wk = new XSSFWorkbook(fs);
if (sheetNum >= sheetCount || sheetName.StartsWith('#'))
{
return null;
}
ISheet sheet = wk.GetSheetAt(sheetNum);
for (int i = 5; i <= sheet.LastRowNum; i++) for (int i = 5; i <= sheet.LastRowNum; i++)
{ {
IRow row = sheet.GetRow(i); IRow row = sheet.GetRow(i);
if (row == null) continue; if (row == null) continue;
var tableExcelRow = new TableExcelRow(); var tableExcelRow = new TableExcelRow();
for (int j = 0; j < headers.Count; j++)
for (int j = 0; j < excelHeader.Count; j++) tableExcelRow.Add(GetCellValue(row.GetCell(j)));
{
var cell = row.GetCell(j);
tableExcelRow.Add(GetCellValue(cell));
}
tableRows.Add(tableExcelRow); tableRows.Add(tableExcelRow);
} }
return new TableExcelData(excelHeader, tableRows); return new ParsedSheet
{
SheetName = sheetName,
Headers = headers,
Data = new TableExcelData(headers, tableRows),
};
} }
catch (Exception ex) catch (Exception ex)
{ {
ex.ToString().WriteErrorLine(); ex.ToString().WriteErrorLine();
sheetName = null;
sheetCount = 0;
return null; return null;
} }
} }
private static string GetCellValue(ICell cell) private static string GetCellValue(ICell cell)
{ {
if (cell == null) if (cell == null)
@@ -121,11 +107,7 @@ namespace ExcelTool
return cell.StringCellValue; return cell.StringCellValue;
case CellType.Numeric: case CellType.Numeric:
if (DateUtil.IsCellDateFormatted(cell)) return DateUtil.IsCellDateFormatted(cell) ? cell.DateCellValue.ToString() : cell.NumericCellValue.ToString();
{
return cell.DateCellValue.ToString();
}
return cell.NumericCellValue.ToString();
case CellType.Boolean: case CellType.Boolean:
return cell.BooleanCellValue ? "1" : "0"; return cell.BooleanCellValue ? "1" : "0";
@@ -138,4 +120,11 @@ namespace ExcelTool
} }
} }
} }
public class ParsedSheet
{
public string SheetName { get; init; }
public List<TableExcelHeader> Headers { get; init; }
public TableExcelData Data { get; init; }
}
} }
+4 -14
View File
@@ -10,16 +10,6 @@ namespace ExcelTool
/// </summary> /// </summary>
public static class FileManager public static class FileManager
{ {
public static bool CreateDir(string dirPath)
{
if (string.IsNullOrEmpty(dirPath))
return false;
if (Directory.Exists(dirPath))
Directory.Delete(dirPath, true);
Directory.CreateDirectory(dirPath);
return true;
}
/// <summary>将数据写入二进制文件(IBinarySerializable 版本)</summary> /// <summary>将数据写入二进制文件(IBinarySerializable 版本)</summary>
public static bool WriteBinaryDataToFile(string filePath, IBinarySerializable data) public static bool WriteBinaryDataToFile(string filePath, IBinarySerializable data)
{ {
@@ -67,7 +57,7 @@ namespace ExcelTool
continue; continue;
} }
ConsoleHelper.WriteErrorLine($"写入二进制文件:数据类型 \"{rawType}\" 未注册,请在 TypeRegistry 中添加"); $"写入二进制文件:数据类型 \"{rawType}\" 未注册,请在 TypeRegistry 中添加".WriteErrorLine();
return false; return false;
} }
@@ -76,7 +66,7 @@ namespace ExcelTool
} }
catch (Exception ex) catch (Exception ex)
{ {
ConsoleHelper.WriteErrorLine(ex.ToString()); ex.ToString().WriteErrorLine();
return false; return false;
} }
} }
@@ -91,7 +81,7 @@ namespace ExcelTool
var elemDesc = TypeRegistry.Get(innerType); var elemDesc = TypeRegistry.Get(innerType);
if (elemDesc == null) if (elemDesc == null)
{ {
ConsoleHelper.WriteErrorLine($"list<T> 的元素类型 \"{innerType}\" 未注册,请在 TypeRegistry 中添加"); $"list<T> 的元素类型 \"{innerType}\" 未注册,请在 TypeRegistry 中添加".WriteErrorLine();
return; return;
} }
@@ -140,7 +130,7 @@ namespace ExcelTool
} }
public static bool WriteToFile(string filePath, string context) => public static bool WriteToFile(string filePath, string context) =>
WriteToFile(filePath, context, Encoding.Default); WriteToFile(filePath, context, new UTF8Encoding(false));
public static bool WriteToFile(string filePath, string context, Encoding encoding) public static bool WriteToFile(string filePath, string context, Encoding encoding)
{ {
+13 -34
View File
@@ -10,53 +10,39 @@ namespace ExcelTool.Parser
/// <summary> /// <summary>
/// 生成对应的 C# Model 类 /// 生成对应的 C# Model 类
/// </summary> /// </summary>
public static bool GenCSharpModel(string fileName, string outputDir, string nameSpace = "") public static bool GenCSharpModel(List<ParsedSheet> parsedSheets, string outputDir, string nameSpace = "")
{ {
if (string.IsNullOrEmpty(fileName))
{
"GenCSharpModel 参数传递有误".WriteErrorLine();
return false;
}
try try
{ {
FileInfo fileInfo = new(fileName); foreach(ParsedSheet sheet in parsedSheets)
if (string.IsNullOrEmpty(outputDir))
outputDir = fileInfo.DirectoryName;
for (int sheetNum = 0; ; sheetNum++)
{ {
var headers = ExcelHelper.ExcelHeaders(fileName, out string sheetName, out int sheetCount, sheetNum); StringBuilder sb = new();
if (headers == null || headers.Count == 0 || sheetName.StartsWith("#") || sheetNum > sheetCount) sb.Append($"/*\n * auto generated by tools(注意:千万不要手动修改本文件)\n * {sheet.SheetName}\n */\n");
break; sb.Append("using System;\nusing System.IO;\nusing System.Collections.Generic;\nusing System.Text;\n\n");
var sb = new StringBuilder();
sb.Append($"/*\n * auto generated by tools(注意:千万不要手动修改本文件)\n * {sheetName}\n */\n");
sb.Append("using System;\nusing System.IO;\nusing System.Collections.Generic;\nusing System.Text;\nusing WKMobile.Generated;\n\n");
if (!string.IsNullOrEmpty(nameSpace)) if (!string.IsNullOrEmpty(nameSpace))
sb.Append($"namespace {nameSpace}\n{{\n"); sb.Append($"namespace {nameSpace}\n{{\n");
// ── 数据行类 ───────────────────────────────────────────────── // ── 数据行类 ─────────────────────────────────────────────────
sb.Append("[Serializable]\n"); sb.Append("[Serializable]\n");
sb.Append($"public partial class {sheetName} : IBinarySerializable\n"); sb.Append($"public partial class {sheet.SheetName} : IBinarySerializable\n");
sb.Append("{\n"); sb.Append("{\n");
foreach (var header in headers) foreach (var header in sheet.Headers)
AppendProperty(sb, header); AppendProperty(sb, header);
AppendDeserializeMethod(sb, headers, sheetName); AppendDeserializeMethod(sb, sheet.Headers, sheet.SheetName);
AppendSerializeMethod(sb, headers, sheetName); AppendSerializeMethod(sb, sheet.Headers, sheet.SheetName);
sb.Append("}\n\n"); sb.Append("}\n\n");
// ── Config 容器类 ───────────────────────────────────────────── // ── Config 容器类 ─────────────────────────────────────────────
AppendConfigClass(sb, sheetName); AppendConfigClass(sb, sheet.SheetName);
if (!string.IsNullOrEmpty(nameSpace)) if (!string.IsNullOrEmpty(nameSpace))
sb.Append("}\n"); sb.Append("}\n");
FileManager.WriteToFile(Path.Combine(outputDir, $"{sheetName}.cs"), sb.ToString()); FileManager.WriteToFile(Path.Combine(outputDir, $"{sheet.SheetName}.cs"), sb.ToString());
} }
return true; return true;
@@ -234,16 +220,9 @@ namespace ExcelTool.Parser
} }
/// <summary>从 TypeDescriptor 反推 reader.ReadXxx() 表达式(用于 list&lt;T&gt; 代码生成)</summary> /// <summary>从 TypeDescriptor 反推 reader.ReadXxx() 表达式(用于 list&lt;T&gt; 代码生成)</summary>
private static string GetReadExpr(TypeDescriptor desc) static string GetReadExpr(TypeDescriptor desc)
{ {
// GenDeserialize 生成的行形如 "\t\tname = reader.ReadXxx();\n" return desc.ReadExpression ?? $"/* unknown read for {desc.TypeName} */";
// 这里简单地从注册表拿一个占位 name 然后截取表达式部分
const string placeholder = "__x__";
var line = desc.GenDeserialize(placeholder).Trim(); // "x = reader.ReadXxx();"
var eqIdx = line.IndexOf('=');
return eqIdx >= 0
? line[(eqIdx + 1)..].TrimEnd(';').Trim() // "reader.ReadXxx()"
: $"/* unknown read for {desc.TypeName} */";
} }
} }
} }
+8 -22
View File
@@ -6,35 +6,21 @@ namespace ExcelTool.Parser
{ {
public static class TableExcelExportBytes public static class TableExcelExportBytes
{ {
public static bool ExportToFile(string fileName, string outputDir = null) public static bool ExportToFile(List<ParsedSheet> parsedSheets, string outputDir = null)
{ {
try try
{ {
FileInfo fileInfo = new(fileName); foreach(ParsedSheet sheet in parsedSheets)
if (string.IsNullOrEmpty(outputDir))
{ {
outputDir = fileInfo.DirectoryName;
}
for (int sheetNum = 0; ; sheetNum++)
{
var tableData = ExcelHelper.ExcelData(fileName, out string sheetName, out int sheetCount, sheetNum);
if (tableData == null || sheetNum >= sheetCount)
break;
// # 开头的 sheet 只跳过
if (sheetName.StartsWith("#"))
continue;
List<Tuple<string, string>> datas = []; List<Tuple<string, string>> datas = [];
//先写入行数,然后每一行的数据一次写入 小写类型、字符串 //先写入行数,然后每一行的数据一次写入 小写类型、字符串
Tuple<string, string> rowCount = new("int", tableData.RowCounts.ToString()); Tuple<string, string> rowCount = new("int", sheet.Data.RowCounts.ToString());
datas.Add(rowCount); datas.Add(rowCount);
foreach (var row in tableData.Rows) foreach (var row in sheet.Data.Rows)
{ {
for (int i = 0; i < tableData.CollonCount; i++) for (int i = 0; i < sheet.Data.CollonCount; i++)
{ {
var type = tableData.Headers[i].FieldType.ToLower(); var type = sheet.Data.Headers[i].FieldType.ToLower();
var data = row.StrList[i]; var data = row.StrList[i];
// 未在 TypeRegistry 注册的类型(且不是 list<T>)当枚举处理,写入 byte // 未在 TypeRegistry 注册的类型(且不是 list<T>)当枚举处理,写入 byte
@@ -46,7 +32,7 @@ namespace ExcelTool.Parser
datas.Add(new Tuple<string, string>(type, data)); datas.Add(new Tuple<string, string>(type, data));
} }
} }
var binaryFilePath = Path.Combine(outputDir, $"{sheetName}.bytes"); var binaryFilePath = Path.Combine(outputDir, $"{sheet.SheetName}.bytes");
FileManager.WriteBinaryDatasToFile(binaryFilePath, datas); FileManager.WriteBinaryDatasToFile(binaryFilePath, datas);
} }
return true; return true;
@@ -59,6 +45,6 @@ namespace ExcelTool.Parser
} }
private static bool IsGenericList(string type) => private static bool IsGenericList(string type) =>
type.StartsWith("list<") && type.EndsWith(">"); type.StartsWith("list<") && type.EndsWith('>');
} }
} }
+14 -35
View File
@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using ExcelTool.Parser; using ExcelTool.Parser;
namespace ExcelTool namespace ExcelTool
@@ -46,45 +45,32 @@ namespace ExcelTool
{ {
outputDataDir = outputCodeDir; outputDataDir = outputCodeDir;
} }
// TODO 使用System.CommandLine重构参数解析
DirectoryInfo dirInfo = new(path); DirectoryInfo dirInfo = new(path);
FileInfo[] csvs = dirInfo.GetFiles("*.csv", SearchOption.AllDirectories);
FileInfo[] excels = dirInfo.GetFiles("*.xlsx", SearchOption.AllDirectories); FileInfo[] excels = dirInfo.GetFiles("*.xlsx", SearchOption.AllDirectories);
if ((csvs.Length <= 0) && (excels.Length <= 0)) if (excels.Length <= 0)
{ {
"当前exe目录或者目标目录没有csv文件或者excels文件,请重新设置目录".WriteErrorLine(); "当前exe目录或者目标目录没有excels文件,请重新设置目录".WriteErrorLine();
} }
else else
{ {
"==========================================================".WriteSuccessLine(); "==========================================================".WriteSuccessLine();
"== 根据csv/xlsx生成模板代码和二进制文件工具 ==".WriteSuccessLine(); "== 根据xlsx生成模板代码和二进制文件工具 ==".WriteSuccessLine();
"== 说明:将exe放在csv/xlsx目录中或者exe或者传入csv根目录 ==".WriteSuccessLine(); "== 说明:将exe放在xlsx目录中或者exe或者传入根目录 ==".WriteSuccessLine();
"==========================================================".WriteSuccessLine(); "==========================================================".WriteSuccessLine();
List<string> genExcels = [];
foreach (FileInfo csv in csvs)
{
//生成对应的xlsx文件
var tempPath = CsvHelper.CsvToXlsx(csv.FullName);
if (string.IsNullOrEmpty(tempPath))
{
$"csv:{csv.FullName}生成xlsx文件出错".WriteErrorLine();
}
else
{
genExcels.Add(tempPath);
}
}
excels = dirInfo.GetFiles("*.xlsx", SearchOption.AllDirectories); excels = dirInfo.GetFiles("*.xlsx", SearchOption.AllDirectories);
//读取 //读取
foreach (var file in excels) foreach (FileInfo file in excels)
{ {
if (file.Name.StartsWith("~$")) return; if (file.Name.StartsWith("~$")) continue;
List<ParsedSheet> sheets = ExcelHelper.ParseAllSheets(file.FullName);
//生成CS文件 //生成CS文件
bool res = GenModels.GenCSharpModel(file.FullName, outputCodeDir, nameSpace); bool res = GenModels.GenCSharpModel(sheets, outputCodeDir, nameSpace);
if (res) if (res)
{ {
$"{file.Name}CS模板生成成功".WriteSuccessLine(); $"{file.Name}CS模板生成成功".WriteSuccessLine();
@@ -95,7 +81,7 @@ namespace ExcelTool
} }
//生成二进制文件,如果list或者vector数据为空则写入0,要根据类型来读取csv的字段数据强转成对应的数据类型然后写入 //生成二进制文件,如果list或者vector数据为空则写入0,要根据类型来读取csv的字段数据强转成对应的数据类型然后写入
res = TableExcelExportBytes.ExportToFile(file.FullName, outputDataDir); res = TableExcelExportBytes.ExportToFile(sheets, outputDataDir);
if (res) if (res)
{ {
$"{file.Name}二进制数据生成成功".WriteSuccessLine(); $"{file.Name}二进制数据生成成功".WriteSuccessLine();
@@ -105,17 +91,10 @@ namespace ExcelTool
$"{file.Name}二进制数据生成失败".WriteErrorLine(); $"{file.Name}二进制数据生成失败".WriteErrorLine();
} }
} }
// TODO 抽象 ExcelProcess 类 处理相关流程
//删除生成的excels // TODO 单元测试
for (int i = genExcels.Count - 1; i >= 0; i--)
{
File.Delete(genExcels[i]);
}
Dictionary<int, string> dics = new();
new List<string>(dics.Values);
//读取测试
//IBinarySerializable newavList = new avatarguideTestConfig(); //IBinarySerializable newavList = new avatarguideTestConfig();
//var readOK = FileManager.ReadBinaryDataFromFile(Path.Combine(path, "avatarguideTest.bytes"), ref newavList); //var readOK = FileManager.ReadBinaryDataFromFile(Path.Combine(path, "avatarguideTest.bytes"), ref newavList);
//if (readOK) //if (readOK)
+6 -2
View File
@@ -29,6 +29,9 @@ namespace ExcelTool
/// 生成 Serialize 方法体片段(变量名 → 代码行) /// 生成 Serialize 方法体片段(变量名 → 代码行)
/// </summary> /// </summary>
public Func<string, string> GenSerialize { get; init; } public Func<string, string> GenSerialize { get; init; }
/// <summary>用于代码生成的单次读取表达式,例如 "reader.ReadInt32()"</summary>
public string ReadExpression { get; init; }
} }
/// <summary> /// <summary>
@@ -158,6 +161,7 @@ namespace ExcelTool
{ {
TypeName = typeName, TypeName = typeName,
CSharpType = csType, CSharpType = csType,
ReadExpression = readExpr,
WriteBinary = writeBinary, WriteBinary = writeBinary,
GenDeserialize = name => $"\t\t{name} = {readExpr};\n", GenDeserialize = name => $"\t\t{name} = {readExpr};\n",
GenSerialize = name => $"\t\twriter.Write({name});\n", GenSerialize = name => $"\t\twriter.Write({name});\n",
@@ -194,7 +198,7 @@ namespace ExcelTool
/// <summary>生成 List&lt;T&gt; 的 DeSerialize 片段</summary> /// <summary>生成 List&lt;T&gt; 的 DeSerialize 片段</summary>
public static string GenListDeserialize(string name, string elemCsType, string readElemExpr) public static string GenListDeserialize(string name, string elemCsType, string readElemExpr)
{ {
var camel = StringExtensions.ToCamelCase(name); string camel = name.ToCamelCase();
return return
$"\t\tvar {camel}Count = reader.ReadInt32();\n" + $"\t\tvar {camel}Count = reader.ReadInt32();\n" +
$"\t\tif ({camel}Count > 0)\n" + $"\t\tif ({camel}Count > 0)\n" +
@@ -231,7 +235,7 @@ namespace ExcelTool
private static string GenVectorListDeserialize(string name) private static string GenVectorListDeserialize(string name)
{ {
var camel = StringExtensions.ToCamelCase(name); string camel = name.ToCamelCase();
return return
$"\t\tvar {camel}Count = reader.ReadInt32();\n" + $"\t\tvar {camel}Count = reader.ReadInt32();\n" +
$"\t\tif ({camel}Count > 0)\n" + $"\t\tif ({camel}Count > 0)\n" +