带有列名的DataReader到.CSV

时间:2015-04-10 12:22:40

标签: c# sql-server

我正在从SqlDataReader生成一个csv文件,但是它没有写出列名,我怎么能让它们写出来呢?我正在使用的代码如下:

SqlConnection conn = new SqlConnection(myconn);
SqlCommand cmd = new SqlCommand("dbo.test", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();

StringBuilder sb = new StringBuilder();
StreamWriter sw = new StreamWriter(myfilePath + "testfile.csv"); 
while (reader.Read())
{
    for (int i = 0; i < reader.FieldCount; i++)
    {
        string value = reader[i].ToString();
        if (value.Contains(","))
            value = "\"" + value + "\"";

        sb.Append(value.Replace(Environment.NewLine, " ") + ",");
    }
    sb.Length--; // Remove the last comma
    sb.AppendLine();
}
conn.Close();
sw.Write(sb.ToString());
sw.Close();

5 个答案:

答案 0 :(得分:9)

读取所有列名称并将其附加到sb然后迭代读者。

SqlDataReader reader = cmd.ExecuteReader();
StringBuilder sb = new StringBuilder();

//Get All column 
var columnNames = Enumerable.Range(0, reader.FieldCount)
                        .Select(reader.GetName) //OR .Select("\""+  reader.GetName"\"") 
                        .ToList();

//Create headers
sb.Append(string.Join(",", columnNames));

//Append Line
sb.AppendLine();

while (reader.Read())
....

答案 1 :(得分:2)

使用此solution我创建了一个扩展名。

/// <summary>
/// 
/// </summary>
/// <param name="reader"></param>
/// <param name="filename"></param>
/// <param name="path">if null/empty will use IO.Path.GetTempPath()</param>
/// <param name="extension">will use csv by default</param>
public static void ToCsv(this IDataReader reader, string filename, string path = null, string extension = "csv")
{
    int nextResult = 0;
    do
    {
        var filePath = Path.Combine(string.IsNullOrEmpty(path) ? Path.GetTempPath() : path, string.Format("{0}.{1}", filename, extension));
        using (StreamWriter writer = new StreamWriter(filePath))
        {
            writer.WriteLine(string.Join(",", Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList()));
            int count = 0;
            while (reader.Read())
            {
                writer.WriteLine(string.Join(",", Enumerable.Range(0, reader.FieldCount).Select(reader.GetValue).ToList()));
                if (++count % 100 == 0)
                {
                    writer.Flush();
                }
            }
        }

        filename = string.Format("{0}-{1}", filename, ++nextResult);
    }
    while (reader.NextResult());
}

答案 2 :(得分:1)

您可以使用SqlDataReader.GetName获取列名称

for (int i = 0; i < reader.FieldCount; i++)
{
    string columnName = reader.GetName(i);
}

您还可以创建如下所示的扩展方法:

public static List<string> ToCSV(this IDataReader dataReader, bool includeHeaderAsFirstRow, string separator)
{
    List<string> csvRows = new List<string>();
    StringBuilder sb = null;

    if (includeHeaderAsFirstRow)
    {
        sb = new StringBuilder();
        for (int index = 0; index < dataReader.FieldCount; index++)
        {
            if (dataReader.GetName(index) != null)
                sb.Append(dataReader.GetName(index));

            if (index < dataReader.FieldCount - 1)
                sb.Append(separator);
        }
        csvRows.Add(sb.ToString());
    }

    while (dataReader.Read())
    {
        sb = new StringBuilder();
        for (int index = 0; index < dataReader.FieldCount - 1; index++)
        {
            if (!dataReader.IsDBNull(index))
            {
                string value = dataReader.GetValue(index).ToString();
                if (dataReader.GetFieldType(index) == typeof(String))
                {
                    //If double quotes are used in value, ensure each are replaced but 2.
                    if (value.IndexOf("\"") >= 0)
                        value = value.Replace("\"", "\"\"");

                    //If separtor are is in value, ensure it is put in double quotes.
                    if (value.IndexOf(separator) >= 0)
                        value = "\"" + value + "\"";
                }
                sb.Append(value);
            }

            if (index < dataReader.FieldCount - 1)
                sb.Append(separator);
        }

        if (!dataReader.IsDBNull(dataReader.FieldCount - 1))
            sb.Append(dataReader.GetValue(dataReader.FieldCount - 1).ToString().Replace(separator, " "));

        csvRows.Add(sb.ToString());
    }
    dataReader.Close();
    sb = null;
    return csvRows;
}

示例:

List<string> rows = null;
using (SqlDataReader dataReader = command.ExecuteReader())
    {
        rows = dataReader.ToCSV(includeHeadersAsFirstRow, separator);
        dataReader.Close();
    }

答案 3 :(得分:1)

我开发了以下高性能扩展程序

static void Main(string[] args)
        {
            SqlConnection sqlCon = new SqlConnection("Removed");
            sqlCon.Open();
            SqlCommand sqlCmd = new SqlCommand("Select * from Table", sqlCon);
            SqlDataReader reader = sqlCmd.ExecuteReader();
            string csv=reader.ToCSVHighPerformance(true);
            File.WriteAllText("Test.CSV", csv);
            reader.Close();
            sqlCon.Close();
        }

<强> Extention:

public static string ToCSVHighPerformance(this IDataReader dataReader, bool includeHeaderAsFirstRow = true,
            string separator = ",")
        {
            DataTable dataTable = new DataTable();
            StringBuilder csvRows = new StringBuilder();
            string row = "";
            int columns ;
            try
            {
                dataTable.Load(dataReader);
                columns= dataTable.Columns.Count;
                //Create Header
                if (includeHeaderAsFirstRow)
                {
                    for (int index = 0; index < columns; index++)
                    {
                        row += (dataTable.Columns[index]);
                        if (index < columns - 1)
                            row += (separator);
                    }
                    row += (Environment.NewLine);
                }
                csvRows.Append(row);

                //Create Rows
                for (int rowIndex = 0; rowIndex < dataTable.Rows.Count; rowIndex++)
                {
                    row = "";
                    //Row
                    for (int index = 0; index < columns - 1; index++)
                    {
                        string value = dataTable.Rows[rowIndex][index].ToString();

                        //If type of field is string
                        if (dataTable.Rows[rowIndex][index] is string)
                        {
                            //If double quotes are used in value, ensure each are replaced by double quotes.
                            if (value.IndexOf("\"") >= 0)
                                value = value.Replace("\"", "\"\"");

                            //If separtor are is in value, ensure it is put in double quotes.
                            if (value.IndexOf(separator) >= 0)
                                value = "\"" + value + "\"";

                            //If string contain new line character
                            while (value.Contains("\r"))
                            {
                                value = value.Replace("\r", "");
                            }
                            while (value.Contains("\n"))
                            {
                                value = value.Replace("\n", "");
                            }
                        }
                        row += value;
                        if (index < columns - 1)
                            row += separator;
                    }
                    dataTable.Rows[rowIndex][columns - 1].ToString().ToString().Replace(separator, " ");
                    row += Environment.NewLine;
                    csvRows.Append(row);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return csvRows.ToString();
        }

答案 4 :(得分:0)

您可以使用SqlDataReader.GetName方法获取列的名称,如下所示:

for(int i = 0; i < reader.FieldCount; i++)
{
    string columnName = reader.GetName(i);
}