c#datatable到csv

有人可以告诉我为什么下面的代码不工作。 数据保存到csv文件中,但数据不分离。 它全部存在于每行的第一个单元格内。

StringBuilder sb = new StringBuilder(); foreach (DataColumn col in dt.Columns) { sb.Append(col.ColumnName + ','); } sb.Remove(sb.Length - 1, 1); sb.Append(Environment.NewLine); foreach (DataRow row in dt.Rows) { for (int i = 0; i < dt.Columns.Count; i++) { sb.Append(row[i].ToString() + ","); } sb.Append(Environment.NewLine); } File.WriteAllText("test.csv", sb.ToString()); 

谢谢。

下面的较短版本可以在Excel中打开,也许你的问题是尾随的逗号

.net = 3.5

 StringBuilder sb = new StringBuilder(); string[] columnNames = dt.Columns.Cast<DataColumn>(). Select(column => column.ColumnName). ToArray(); sb.AppendLine(string.Join(",", columnNames)); foreach (DataRow row in dt.Rows) { string[] fields = row.ItemArray.Select(field => field.ToString()). ToArray(); sb.AppendLine(string.Join(",", fields)); } File.WriteAllText("test.csv", sb.ToString()); 

.net> = 4.0

正如Tim指出的那样,如果你使用.net> = 4,你可以缩短它:

 StringBuilder sb = new StringBuilder(); IEnumerable<string> columnNames = dt.Columns.Cast<DataColumn>(). Select(column => column.ColumnName); sb.AppendLine(string.Join(",", columnNames)); foreach (DataRow row in dt.Rows) { IEnumerable<string> fields = row.ItemArray.Select(field => field.ToString()); sb.AppendLine(string.Join(",", fields)); } File.WriteAllText("test.csv", sb.ToString()); 

正如Christianbuild议的那样,如果你想处理在字段中转义的特殊字符,用下面的代码来replace循环块:

 foreach (DataRow row in dt.Rows) { IEnumerable<string> fields = row.ItemArray.Select(field => string.Concat("\"", field.ToString().Replace("\"", "\"\""), "\"")); sb.AppendLine(string.Join(",", fields)); } 

最后的build议是,可以逐行写入csv内容,而不是整个文档,以避免在内存中出现大文档。

我把它包装成一个扩展类,它允许你调用:

 myDataTable.WriteToCsvFile("C:\\MyDataTable.csv"); 

在任何DataTable上。

 public static class DataTableExtensions { public static void WriteToCsvFile(this DataTable dataTable, string filePath) { StringBuilder fileContent = new StringBuilder(); foreach (var col in dataTable.Columns) { fileContent.Append(col.ToString() + ","); } fileContent.Replace(",", System.Environment.NewLine, fileContent.Length - 1, 1); foreach (DataRow dr in dataTable.Rows) { foreach (var column in dr.ItemArray) { fileContent.Append("\"" + column.ToString() + "\","); } fileContent.Replace(",", System.Environment.NewLine, fileContent.Length - 1, 1); } System.IO.File.WriteAllText(filePath, fileContent.ToString()); } } } 

一个基于Paul Grimshaw的答案的新扩展function。 我清理了它,并添加了处理意外数据的能力。 (空数据,embedded式行情和逗号在标题中…)

它也返回一个更灵活的string。 如果表对象不包含任何结构,则返回Null。

  public static string ToCsv(this DataTable dataTable) { StringBuilder sbData = new StringBuilder(); // Only return Null if there is no structure. if (dataTable.Columns.Count == 0) return null; foreach (var col in dataTable.Columns) { if (col == null) sbData.Append(","); else sbData.Append("\"" + col.ToString().Replace("\"", "\"\"") + "\","); } sbData.Replace(",", System.Environment.NewLine, sbData.Length - 1, 1); foreach (DataRow dr in dataTable.Rows) { foreach (var column in dr.ItemArray) { if (column == null) sbData.Append(","); else sbData.Append("\"" + column.ToString().Replace("\"", "\"\"") + "\","); } sbData.Replace(",", System.Environment.NewLine, sbData.Length - 1, 1); } return sbData.ToString(); } 

你这样称呼它:

 var csvData = dataTableOject.ToCsv(); 

如果你的调用代码引用了System.Windows.Forms程序集,你可能会考虑一个截然不同的方法。 我的策略是使用已经由框架提供的function,在很less的代码行中完成这些function,而不必循环遍历行和列。 下面的代码是通过编程方式创build一个DataGridView ,并将DataGridView.DataSource设置为DataTable 。 接下来,我以编程方式selectDataGridView中的所有单元格(包括标题),并调用DataGridView.GetClipboardContent() ,将结果放入Windows Clipboard 。 然后,将剪贴板的内容粘贴到File.WriteAllText()的调用中,确保将“粘贴”的格式指定为TextDataFormat.CommaSeparatedValue

这里是代码:

 public static void DataTableToCSV(DataTable Table, string Filename) { using(DataGridView dataGrid = new DataGridView()) { // Save the current state of the clipboard so we can restore it after we are done IDataObject objectSave = Clipboard.GetDataObject(); // Set the DataSource dataGrid.DataSource = Table; // Choose whether to write header. Use EnableWithoutHeaderText instead to omit header. dataGrid.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText; // Select all the cells dataGrid.SelectAll(); // Copy (set clipboard) Clipboard.SetDataObject(dataGrid.GetClipboardContent()); // Paste (get the clipboard and serialize it to a file) File.WriteAllText(Filename,Clipboard.GetText(TextDataFormat.CommaSeparatedValue)); // Restore the current state of the clipboard so the effect is seamless if(objectSave != null) // If we try to set the Clipboard to an object that is null, it will throw... { Clipboard.SetDataObject(objectSave); } } } 

注意我还要确保在开始之前保留剪贴板的内容,并在完成后恢复,以便用户下次尝试粘贴时不会收到一堆意外的垃圾。 这种方法的主要注意事项是1)你的类必须引用System.Windows.Forms ,这可能不是在数据抽象层中的情况,2)你的程序集必须作为.NET 4.5框架的目标,因为DataGridView的确如此4.0中不存在,3)如果剪贴板被另一个进程使用,该方法将失败。

无论如何,这种方法可能不适合你的情况,但它是有趣的,也可以是你的工具箱中的另一个工具。

尝试把; 而不是,

希望它有帮助

我最近做了这个,但是在我的价值观里面加了双引号。

例如,更改这两行:

 sb.Append("\"" + col.ColumnName + "\","); ... sb.Append("\"" + row[i].ToString() + "\","); 

尝试改变sb.Append(Environment.NewLine);sb.AppendLine();

 StringBuilder sb = new StringBuilder(); foreach (DataColumn col in dt.Columns) { sb.Append(col.ColumnName + ','); } sb.Remove(sb.Length - 1, 1); sb.AppendLine(); foreach (DataRow row in dt.Rows) { for (int i = 0; i < dt.Columns.Count; i++) { sb.Append(row[i].ToString() + ","); } sb.AppendLine(); } File.WriteAllText("test.csv", sb.ToString()); 

读这个和这个 ?


更好的实施将是

 var result = new StringBuilder(); for (int i = 0; i < table.Columns.Count; i++) { result.Append(table.Columns[i].ColumnName); result.Append(i == table.Columns.Count - 1 ? "\n" : ","); } foreach (DataRow row in table.Rows) { for (int i = 0; i < table.Columns.Count; i++) { result.Append(row[i].ToString()); result.Append(i == table.Columns.Count - 1 ? "\n" : ","); } } File.WriteAllText("test.csv", result.ToString()); 

错误是列表分隔符。

而不是写作sb.Append(something... + ',')你应该把类似sb.Append(something... + System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator);

您必须将操作系统中configuration的列表分隔符(如上例所示)或要在其中监视文件的客户端计算机中的列表分隔符。 另一种select是在app.config或web.config中将其configuration为应用程序的参数。

4行代码:

 public static string ToCSV(DataTable tbl) { StringBuilder strb = new StringBuilder(); //column headers strb.AppendLine(string.Join(",", tbl.Columns.Cast<DataColumn>() .Select(s => "\"" + s.ColumnName + "\""))); //rows tbl.AsEnumerable().Select(s => strb.AppendLine( string.Join(",", s.ItemArray.Select( i => "\"" + i.ToString() + "\"")))).ToList(); return strb.ToString(); } 

注意最后的ToList()是重要的; 我需要一些东西来强制expression评估。 如果我是代码打高尔夫,我可以用Min()来代替。

还要注意,由于最后一次调用AppendLine() ,结果将在最后换行。 你可能不想要这个。 你可以简单地调用TrimEnd()来删除它。

这是一个增强的vc-74的post,处理逗号的方式和Excel一样。 如果数据有一个逗号,Excel会在数据周围引用引号,但如果数据没有逗号,则不会引用该引号。

  public static string ToCsv(this DataTable inDataTable, bool inIncludeHeaders = true) { var builder = new StringBuilder(); var columnNames = inDataTable.Columns.Cast<DataColumn>().Select(column => column.ColumnName); if (inIncludeHeaders) builder.AppendLine(string.Join(",", columnNames)); foreach (DataRow row in inDataTable.Rows) { var fields = row.ItemArray.Select(field => field.ToString().WrapInQuotesIfContains(",")); builder.AppendLine(string.Join(",", fields)); } return builder.ToString(); } public static string WrapInQuotesIfContains(this string inString, string inSearchString) { if (inString.Contains(inSearchString)) return "\"" + inString+ "\""; return inString; } 

如果有人绊倒在这,我用File.ReadAllText来获取CSV数据,然后我修改它,并用File.WriteAllText写回来。 \ r \ n CRLF很好,但是当Excel打开它时忽略了这些标签。 (到目前为止,此线程中的所有解决scheme都使用逗号分隔符,但这并不重要。)记事本在生成的文件中显示与源文件中相同的格式。 一个差异甚至显示文件相同。 但是当我用二进制编辑器在Visual Studio中打开文件时,我得到了一个线索。 源文件是Unicode,但目标是ASCII 。 为了解决这个问题,我修改了第三个参数设置为System.Text.Encoding.Unicode的 ReadAllText和WriteAllText,并从那里Excel能够打开更新的文件。

要写入文件,我认为以下方法是最有效和最直接的:(如果需要,可以添加引号)

 public static void WriteCsv(DataTable dt, string path) { using (var writer = new StreamWriter(path)) { writer.WriteLine(string.Join(",", dt.Columns.Cast<DataColumn>().Select(dc => dc.ColumnName))); foreach (DataRow row in dt.Rows) { writer.WriteLine(string.Join(",", row.ItemArray)); } } } 

可能最简单的方法是使用:

https://github.com/ukushu/DataExporter

特别是在dataTable单元格内包含/r/n字符或分隔符的数据表中。

只有你需要写下面的代码:

 Csv csv = new Csv("\t");//Needed delimiter var columnNames = dt.Columns.Cast<DataColumn>(). Select(column => column.ColumnName).ToArray(); csv.AddRow(columnNames); foreach (DataRow row in dt.Rows) { var fields = row.ItemArray.Select(field => field.ToString()).ToArray; csv.AddRow(fields); } csv.Save(); 
 StringBuilder sb = new StringBuilder(); SaveFileDialog fileSave = new SaveFileDialog(); IEnumerable<string> columnNames = tbCifSil.Columns.Cast<DataColumn>(). Select(column => column.ColumnName); sb.AppendLine(string.Join(",", columnNames)); foreach (DataRow row in tbCifSil.Rows) { IEnumerable<string> fields = row.ItemArray.Select(field =>string.Concat("\"", field.ToString().Replace("\"", "\"\""), "\"")); sb.AppendLine(string.Join(",", fields)); } fileSave.ShowDialog(); File.WriteAllText(fileSave.FileName, sb.ToString()); 
 public void ExpoetToCSV(DataTable dtDataTable, string strFilePath) { StreamWriter sw = new StreamWriter(strFilePath, false); //headers for (int i = 0; i < dtDataTable.Columns.Count; i++) { sw.Write(dtDataTable.Columns[i].ToString().Trim()); if (i < dtDataTable.Columns.Count - 1) { sw.Write(","); } } sw.Write(sw.NewLine); foreach (DataRow dr in dtDataTable.Rows) { for (int i = 0; i < dtDataTable.Columns.Count; i++) { if (!Convert.IsDBNull(dr[i])) { string value = dr[i].ToString().Trim(); if (value.Contains(',')) { value = String.Format("\"{0}\"", value); sw.Write(value); } else { sw.Write(dr[i].ToString().Trim()); } } if (i < dtDataTable.Columns.Count - 1) { sw.Write(","); } } sw.Write(sw.NewLine); } sw.Close(); } 

模仿Excel CSV:

 public static string Convert(DataTable dt) { StringBuilder sb = new StringBuilder(); IEnumerable<string> columnNames = dt.Columns.Cast<DataColumn>(). Select(column => column.ColumnName); sb.AppendLine(string.Join(",", columnNames)); foreach (DataRow row in dt.Rows) { IEnumerable<string> fields = row.ItemArray.Select(field => { string s = field.ToString().Replace("\"", "\"\""); if(s.Contains(',')) s = string.Concat("\"", s, "\""); return s; }); sb.AppendLine(string.Join(",", fields)); } return sb.ToString().Trim(); } 

如果所有数据仍在第一个单元格中,则意味着您打开该文件的应用程序正在等待另一个分隔符。 MSExcel可以处理逗号作为分隔符,除非您另有指定。

Interesting Posts