CmdExcelToCsv.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using ExcelDataReader;
  2. using System.Collections.Concurrent;
  3. using System.Data;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. namespace etoy
  7. {
  8. internal class CmdExcelToCsv : Command
  9. {
  10. private int _total = 0;
  11. private readonly List<Exception> _errors = new List<Exception>();
  12. private readonly ConcurrentStack<string> _dones = new ConcurrentStack<string>();
  13. private readonly Regex _removeStart = new Regex("^( *)[\n\r\t]+");
  14. private readonly Regex _removeEnd = new Regex("[\n\r\t]+( *)$", RegexOptions.RightToLeft);
  15. public override string Description => "Excel转Csv";
  16. protected override void OnProcess()
  17. {
  18. if (Directory.Exists(Context.Option.CsvOutput))
  19. Directory.Delete(Context.Option.CsvOutput, true);
  20. Directory.CreateDirectory(Context.Option.CsvOutput);
  21. string csvOutput = Context.Option.CsvOutput;
  22. var files = Directory.GetFiles(Context.Option.ExcelInput, "*.xlsx", SearchOption.AllDirectories).Where(file => !file.Contains("~$")).ToArray();
  23. _total = files.Length;
  24. Task.Factory.StartNew(OnLoop);
  25. Start(files, csvOutput);
  26. }
  27. private void OnLoop()
  28. {
  29. while (_dones.Count < _total)
  30. {
  31. Thread.Sleep(1);
  32. }
  33. if (_errors.Count > 0)
  34. {
  35. SetException(new Exception(string.Join('\n', (from e in _errors select $"## ERROR: {e}").ToArray())));
  36. }
  37. else
  38. {
  39. Completed();
  40. }
  41. }
  42. private void Start(string[] files, string output)
  43. {
  44. for (int i = 0, length = files.Length; i < length; ++i)
  45. {
  46. var file = files[i];
  47. Task.Factory.StartNew(index =>
  48. {
  49. try
  50. {
  51. Convert(file, output);
  52. _dones.Push(file);
  53. SetProgress(_dones.Count / (float)_total);
  54. }
  55. catch (Exception e)
  56. {
  57. --_total;
  58. _errors.Add(e);
  59. }
  60. }, i);
  61. }
  62. }
  63. private string GetTableName(DataTable dt)
  64. {
  65. var result = dt.TableName.Trim();
  66. result = result
  67. .Replace("\r", string.Empty)
  68. .Replace("\n", string.Empty)
  69. .Replace("\t", string.Empty);
  70. if (result.Length > 64)
  71. result = result.Substring(0, 64);
  72. return result;
  73. }
  74. private void Convert(string source, string destination)
  75. {
  76. using var excel = new FileStream(source, FileMode.Open, FileAccess.Read);
  77. var reader = ExcelReaderFactory.CreateReader(excel);
  78. var tables = reader.AsDataSet().Tables;
  79. var sb = new StringBuilder();
  80. string excelFileName = Path.GetFileNameWithoutExtension(source);
  81. foreach (DataTable table in tables)
  82. {
  83. if (table.TableName.Contains('#'))
  84. continue;
  85. sb.Clear();
  86. string extension;
  87. string tableName;
  88. var rowOffset = 1; // 正式数据行数偏移值
  89. if (excelFileName == "__Metadata" || excelFileName == "共用枚举结构体")
  90. {
  91. extension = ".metadata";
  92. tableName = "Metadata";
  93. }
  94. else if (excelFileName == "__KeyValue" || excelFileName == "Key_Value")
  95. {
  96. extension = ".kv";
  97. tableName = "KeyValue";
  98. }
  99. else
  100. {
  101. extension = ".csv";
  102. tableName = GetTableName(table);
  103. rowOffset = 4;// 前4行0-3(字段名,字段类型,tag,字段描述)不需要保留\n\t等等
  104. }
  105. string csvName = string.Concat(tableName, extension);
  106. string csvPath = Path.Combine(destination, csvName);
  107. if (File.Exists(csvPath))
  108. throw new Exception($"表重复了, Name: {tableName}, ExcelName: {excelFileName}");
  109. int rows = table.Rows.Count;
  110. int columns = table.Columns.Count;
  111. if (rows == 0)
  112. continue;
  113. for (int i = 0; i < rows; ++i)
  114. {
  115. if (i < rowOffset)
  116. {
  117. for (int j = 0; j < columns; ++j)
  118. {
  119. string value = table.Rows[i][j].ToString()
  120. .Replace("\t", string.Empty)
  121. .Replace("\n", string.Empty)
  122. .Replace("\r", string.Empty)
  123. .Replace("\"", "\"\"");
  124. sb.Append($"\"{value}\"");
  125. if (j < columns - 1)
  126. sb.Append(',');
  127. }
  128. }
  129. else
  130. {
  131. for (int j = 0; j < columns; ++j)
  132. {
  133. string value = table.Rows[i][j].ToString();
  134. string value1 = _removeStart.Replace(value, "$1");
  135. string value2 = _removeEnd.Replace(value1, "$1");
  136. string value3 = value2
  137. .Replace("\t", string.Empty)
  138. .Replace("\n", "\\n")
  139. .Replace("\r", "\\n")
  140. .Replace("\"", "\"\"");
  141. sb.Append($"\"{value3}\"");
  142. if (j < columns - 1)
  143. sb.Append(',');
  144. }
  145. }
  146. sb.AppendLine();
  147. }
  148. File.WriteAllText(csvPath, sb.ToString(), Encoding.UTF8);
  149. }
  150. }
  151. }
  152. }