c#datatable to csv

Dar*_*ung 104 c# csv delimited-text

有人可以告诉我为什么下面的代码不起作用.数据将保存到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());
Run Code Online (Sandbox Code Playgroud)

谢谢.

vc *_* 74 216

以下较短版本在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());
Run Code Online (Sandbox Code Playgroud)

.net> = 4.0

正如蒂姆指出的那样,如果你在.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());
Run Code Online (Sandbox Code Playgroud)

正如Christian所建议的那样,如果你想处理在字段中转义的特殊字符,请将循环块替换为:

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

最后一个建议是,您可以逐行编写csv内容而不是整个文档,以避免在内存中有大文档.

  • 此方法不会考虑列值中的逗号. (18认同)
  • 不需要将`ItemArray`复制到新的`String []`,你可以省略`.ToArray()`和.NET 4并使用[`String.Join` overload](http://msdn.microsoft. com/en-us/library/dd992421.aspx)采用`IEnumerable <T>`(已编辑). (2认同)
  • @TimSchmelter,是的,但这些重载是在.net4中引入的,如果OP使用.net <4,代码将无法编译 (2认同)
  • 相反,IEnumerable <string> fields = row.ItemArray.Select(field => field.ToString().Replace("\"","\"\"")); sb.AppendLine("\""+ string.Join ("\",\"",字段)+"\""); (2认同)
  • @ Si8是什么意思?该答案仅使用db组件,而&nbsp是HTML / XML文档的典型代表。除非表明确包含`&nbsp;`,否则不是上面的代码产生它 (2认同)

Pau*_*haw 36

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

myDataTable.WriteToCsvFile("C:\\MyDataTable.csv");
Run Code Online (Sandbox Code Playgroud)

在任何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());
    }
}
Run Code Online (Sandbox Code Playgroud)


Ant*_*yVO 23

基于Paul Grimshaw答案的新扩展函数.我清理了它并添加了处理意外数据的能力.(空数据,嵌入式引号和标题中的逗号......)

它还返回一个更灵活的字符串.如果表对象不包含任何结构,则返回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();
    }
Run Code Online (Sandbox Code Playgroud)

你这叫它如下:

var csvData = dataTableOject.ToCsv();
Run Code Online (Sandbox Code Playgroud)

  • 这是这里其余的最好的。做得好。谢谢 (2认同)

Ada*_*ite 10

如果您的调用代码引用了System.Windows.Forms程序集,您可能会考虑采用完全不同的方法.我的策略是使用框架已经提供的函数在很少的代码行中实现这一点,而不必遍历列和行.下面的代码是以编程方式创建一个动态DataGridView并设置DataGridView.DataSourceDataTable.接下来,我以编程方式选择DataGridView并调用所有单元格(包括标题)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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

无论如何,这种方法可能不适合您的情况,但它仍然很有趣,并且可以是您工具箱中的另一个工具.

  • 很好,但是如果有人同时使用机器并在关键时刻将某些东西放入剪贴板,该怎么办。 (2认同)

Nei*_*ght 8

尝试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());
Run Code Online (Sandbox Code Playgroud)


Ben*_*ben 6

我最近这样做,但包括我的价值观的双引号.

例如,更改以下两行:

sb.Append("\"" + col.ColumnName + "\","); 
...
sb.Append("\"" + row[i].ToString() + "\","); 
Run Code Online (Sandbox Code Playgroud)


nav*_*een 6

这个这个


一个更好的实施将是

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());
Run Code Online (Sandbox Code Playgroud)


小智 6

错误是列表分隔符.

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

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


use*_*861 6

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();
}
Run Code Online (Sandbox Code Playgroud)

请注意,ToList()结尾处很重要;我需要一些东西来强制进行表达式评估。如果我是打高尔夫球的代码,则可以Min()改用。

另请注意,由于最后一次调用,结果末尾会有换行符AppendLine()。您可能不想要这个。您只需调用TrimEnd()即可将其删除。


ale*_*exl 5

试着;代替,

希望能帮助到你


Stu*_*222 5

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

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)