C# WinForm导入CSV后实现数据转置(列转行)的问题及解决
C# WinForm实现CSV数据转置功能问题
我正在使用C#开发Windows Form桌面应用,希望实现用户导入CSV文件后将数据转置(列转为行)的功能,请问如何编写对应代码?
我已编写导入按钮的代码:
private void btnImport_Click(object sender, System.EventArgs e) { try { if (txtCSVFolderPath.Text == "") { MessageBox.Show("The Folder Path TextBox cannot be empty.", "Warning"); return; } else if (txtCSVFilePath.Text == "") { MessageBox.Show("The File Path TextBox cannot be empty.", "Warning"); return; } else { ConnectCSV(); btnUpload.Enabled = true; } } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { } }
以及ConnectCSV方法:
public DataSet ConnectCSV() { DataSet ds = new DataSet(); string fileName = openFileDialogCSVFilePath.FileName; CsvReader reader = new CsvReader(fileName); ds = reader.RowEnumerator; dGridCSVdata.DataSource = ds; dGridCSVdata.DataMember = "TheData"; return ds; }
更新:转置代码无效果的问题
我尝试使用StringBuilder实现转置,但没有效果,请问问题出在哪里?或者有没有其他实现方法?
我的RowEnumerator代码:
public DataSet RowEnumerator { get { if (null == __reader) throw new System.ApplicationException("I can't start reading without CSV input."); __rowno = 0; string sLine; string sNextLine; DataSet ds = new DataSet(); DataTable dt = ds.Tables.Add("TheData"); while (null != (sLine = __reader.ReadLine())) { while (rexRunOnLine.IsMatch(sLine) && null != (sNextLine = __reader.ReadLine())) sLine += "\n" + sNextLine; __rowno++; DataRow dr = dt.NewRow(); string[] values = rexCsvSplitter.Split(sLine); for (int i = 0; i < values.Length; i++) { values[i] = Csv.Unescape(values[i]); if (__rowno == 1) { dt.Columns.Add(values[i].Trim()); } else { if (Csv.CharNotAllowes(values[i])) { dr[i] = values[i].Trim(); } } } if (__rowno != 1) { dt.Rows.Add(dr); } } StringBuilder sb = new StringBuilder();// code I add for transpose the data table for (int u = 0; u < dt.Columns.Count; u++) { for (int i = 0; i < dt.Rows.Count; i++) { sb.Append(dt.Rows[i][u].ToString()); if (i < dt.Rows.Count - 1) { sb.Append(';'); } } sb.AppendLine(); } File.WriteAllText("C:\\Users\\Desktop\\Output.csv", sb.ToString()); __reader.Close(); return ds; } }
问题分析
你当前的转置代码存在几个关键问题:
- 未包含表头信息:原CSV的表头(第一行)没有被加入转置结果,导致输出的转置CSV缺少列名标识
- 空值未处理:直接调用
dt.Rows[i][u].ToString(),如果单元格为空(DBNull.Value)会引发异常 - 分隔符不一致:原CSV使用逗号分隔,但转置结果用分号,可能不符合预期格式
- 未更新界面显示:转置结果仅写入文件,没有绑定到
dGridCSVdata,所以你无法在界面看到转置效果
解决方案
方案1:修复现有StringBuilder转置逻辑
修改RowEnumerator中的StringBuilder部分,补上表头处理、空值判断和统一分隔符:
StringBuilder sb = new StringBuilder(); // 先处理表头:将原表头作为转置后每一行的第一个元素 for (int colIndex = 0; colIndex < dt.Columns.Count; colIndex++) { // 添加表头 sb.Append(dt.Columns[colIndex].ColumnName); // 添加当前列的所有行数据 for (int rowIndex = 0; rowIndex < dt.Rows.Count; rowIndex++) { sb.Append(','); // 处理空值,避免ToString()报错 var cellValue = dt.Rows[rowIndex][colIndex]; sb.Append(cellValue == DBNull.Value ? "" : cellValue.ToString().Trim()); } sb.AppendLine(); } // 注意:路径最好让用户选择,避免硬编码导致权限或路径不存在问题 File.WriteAllText("C:\\Users\\Desktop\\Transposed_Output.csv", sb.ToString());
方案2:创建转置后的DataTable(推荐)
这种方法可以将转置结果绑定到DataGridView,同时也方便导出CSV,更符合WinForm的交互逻辑:
首先添加一个转置方法:
private DataTable TransposeDataTable(DataTable originalTable) { DataTable transposedTable = new DataTable("TransposedData"); // 转置后的第一列是原表的列名,后续列对应原表的每一行 transposedTable.Columns.Add("Column_Name"); for (int rowIndex = 0; rowIndex < originalTable.Rows.Count; rowIndex++) { transposedTable.Columns.Add($"Row_{rowIndex + 1}"); } // 遍历原表的每一列,生成转置后的每一行 foreach (DataColumn originalCol in originalTable.Columns) { DataRow newRow = transposedTable.NewRow(); newRow["Column_Name"] = originalCol.ColumnName; for (int rowIndex = 0; rowIndex < originalTable.Rows.Count; rowIndex++) { var cellValue = originalTable.Rows[rowIndex][originalCol]; newRow[rowIndex + 1] = cellValue ?? DBNull.Value; } transposedTable.Rows.Add(newRow); } return transposedTable; }
然后在ConnectCSV方法中调用,更新界面显示:
public DataSet ConnectCSV() { DataSet ds = new DataSet(); string fileName = openFileDialogCSVFilePath.FileName; CsvReader reader = new CsvReader(fileName); ds = reader.RowEnumerator; // 获取原数据表并转置 DataTable originalTable = ds.Tables["TheData"]; DataTable transposedTable = TransposeDataTable(originalTable); // 将转置后的表加入DataSet,绑定到DataGridView ds.Tables.Add(transposedTable); dGridCSVdata.DataSource = ds; dGridCSVdata.DataMember = "TransposedData"; // 导出转置后的CSV(可选) ExportDataTableToCsv(transposedTable, "C:\\Users\\Desktop\\Transposed_Output.csv"); btnUpload.Enabled = true; return ds; } // 添加CSV导出辅助方法 private void ExportDataTableToCsv(DataTable dt, string filePath) { StringBuilder sb = new StringBuilder(); // 写入表头 string[] columnNames = dt.Columns.Cast<DataColumn>().Select(col => col.ColumnName).ToArray(); sb.AppendLine(string.Join(",", columnNames)); // 写入行数据 foreach (DataRow row in dt.Rows) { string[] fields = row.ItemArray.Select(field => field == DBNull.Value ? "" : $"\"{field.ToString().Replace("\"", "\"\"")}\"" ).ToArray(); sb.AppendLine(string.Join(",", fields)); } File.WriteAllText(filePath, sb.ToString()); }
内容的提问来源于stack exchange,提问作者nadyaggy
相关产品推荐
相关产品推荐

