如何修改代码实现按指定区域导出DataTable数据到独立CSV文件
解决CSV导出仅包含对应区域数据的问题
你的问题核心在于数据累积写入和几处小的代码错误,我帮你拆解问题并给出修改方案:
问题根源
- 你在循环外部创建了
StringBuilder sb,每次处理一个区域时,都会把新数据追加到同一个sb里,导致后面的文件会包含前面所有区域的数据。 - 代码里用了
dt.AsEnumerable(),但你实际的数据源是regionInfo这个DataTable,dt并没有定义,这是笔误。 - 文件名里直接用
row会输出对象的默认ToString()结果(比如<>f__AnonymousType0开头的字符串),而不是区域名称。
修改步骤
- 把
StringBuilder sb的初始化移到每个区域的循环内部,确保每个区域都有独立的字符串构建器,不会累积其他区域的数据。 - 将
dt.AsEnumerable()替换为regionInfo.AsEnumerable(),指向正确的数据源。 - 文件名里的
row改为row.Region,生成正确的区域文件名。 - 每个区域处理时,先写入CSV的列名,再写入该区域的行数据。
修改后的完整代码
private void GenerateRegionTest() { DataTable regionInfo = new DataTable(); regionInfo.Columns.Add("storeID", typeof(int)); regionInfo.Columns.Add("storeName", typeof(string)); regionInfo.Columns.Add("Region", typeof(string)); regionInfo.Rows.Add(25, "Store 1", "Region 1"); regionInfo.Rows.Add(50, "Store 2", "Region 1"); regionInfo.Rows.Add(10, "Store 3", "Region 1"); regionInfo.Rows.Add(21, "Store 4", "Region 1"); regionInfo.Rows.Add(251, "Store 11", "Region 11"); regionInfo.Rows.Add(501, "Store 21", "Region 11"); regionInfo.Rows.Add(101, "Store 31", "Region 11"); regionInfo.Rows.Add(211, "Store 41", "Region 11"); regionInfo.Rows.Add(215, "Store 12", "Region 12"); regionInfo.Rows.Add(510, "Store 22", "Region 12"); regionInfo.Rows.Add(110, "Store 32", "Region 12"); regionInfo.Rows.Add(211, "Store 42", "Region 12"); // 修正数据源,使用regionInfo而不是未定义的dt var regionGroups = regionInfo.AsEnumerable() .GroupBy(row => row.Field<string>("Region")) .Select(group => new { Region = group.Key, DataRowList = group.OrderBy(row => row.Field<string>("storeName")).ToList() }) .OrderBy(x => x.Region) .ToList(); // 遍历每个区域分组 foreach (var regionGroup in regionGroups) { // 每个区域新建一个StringBuilder,避免数据累积 StringBuilder sb = new StringBuilder(); // 写入CSV列名 var columnNames = regionInfo.Columns.Cast<DataColumn>().Select(col => $"\"{col.ColumnName}\""); sb.AppendLine(string.Join(",", columnNames)); // 写入当前区域的所有行 foreach (var dataRow in regionGroup.DataRowList) { IEnumerable<string> fields = dataRow.ItemArray.Select(field => $"\"{field.ToString().Replace("\"", "\\\"")}\""); sb.AppendLine(string.Join(",", fields)); } // 生成正确的文件名,使用区域名称 string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); string fileName = Path.Combine(desktopPath, $"{regionGroup.Region}Breakout.csv"); File.WriteAllText(fileName, sb.ToString()); } }
修改后的逻辑说明
现在每次处理一个区域时:
- 会创建一个全新的
StringBuilder,不会继承之前区域的数据。 - 先写入该CSV的列名(保持表头一致)。
- 只遍历当前区域的行数据,追加到sb里。
- 最后将当前区域的完整数据写入对应的CSV文件,这样每个文件就只会包含对应区域的内容了。
内容的提问来源于stack exchange,提问作者JamesFisher
相关产品推荐
相关产品推荐

