使用阅读器将列提供到csv文件中

时间:2013-11-15 19:02:10

标签: c# csv sqlconnection

我有一个存储过程,它将返回0行或更多行或帐号的列。

如果0行我当然不需要做任何事情,但如果返回1个或更多,我需要将这些帐号扔到csv文件中。

返回的数据如下所示:

100000
200000
286598

这是我的方法:

private static void ThirtyMinuteUpload(DateTime today)
{
    using (SqlConnection connection = new SqlConnection(connString))
    {
        using (SqlCommand command = new SqlCommand("mySP", connection))
        {
            command.CommandType = CommandType.StoredProcedure;

            connection.Open();
            if (command.ExecuteReader().HasRows)
            {
                // Create csv
            }
        }
    }
}

我需要将这些文件从我的阅读器中输入csv并使用传入的today变量将文件命名为:

exlcusion_mmddyyhhmmss.csv 

我从未使用过文件创建功能,现在它可以保存到我的桌面上。是容易做的事情吗?

3 个答案:

答案 0 :(得分:1)

我会做这样的事情:

更新:修复了最后一个逗号问题。

using (SqlDataReader dr = command.ExecuteReader()) 
{
   if (dr.HasRows()) 
   {           
      string dateFormatted = today.ToString("MMddyyhhmmss");
      string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
      var writer = new StreamWriter(String.Format("{0}\exclusion_{1}.csv",
         path, dateFormatted);

      var cont = true;
      while (cont) 
      {
         // Grab the accountid before we read ahead
         var accId = dr["accountid"];

         // Read ahead to check if we've read the last record
         cont = dr.Read();

         // Last record, don't add comma
         if (!cont) 
         {
            writer.Write(accId); 
         }
         else 
         { 
            writer.Write(accId + ",");
         }
      }
   }
}

答案 1 :(得分:0)

private static void ThirtyMinuteUpload(DateTime today)
{
    using (var cn = new SqlConnection(connString))
    using (var cmd = new SqlCommand("mySP", cn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cn.Open();

        using (var rdr = cmd.ExecuteReader())
        {
            if (!rdr.HasRows) return;

            var fileName = string.Format("{0}{1}exclusion_{2:MMddyyHHmmss}.csv",
                Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
                Path.PathSeparator,
                today);

            using (var writer = new StreamWriter(fileName))
            {
                while (rdr.Read())
                {
                    writer.WriteLine(rdr.GetString(0));
                }
            }
        }
    }
}

答案 2 :(得分:0)

这是对您的问题的更抽象的答案。我没有使用SqlDataReader,而是编写了一个通用函数,它将System.Data.IDataReaderSystem.Data.SqlClient.SqlDataReader只是一个类)的任何实现者的数据写入任何System.IO.Stream ,包括文件(使用FileStream)。

/// <summary>
/// Writes the data from a given <see cref="IDataReader"/> <paramref name="reader"/> to the <paramref name="output"/> <see cref="Stream"/>.
/// There are optional parameters for writing a header, specifying the encoding, the buffer size, and whether or not the stream should be
/// closed when we're done reading.
/// </summary>
/// <param name="reader">Any object which implements <see cref="IDataReader"/>-- most likely a <see cref="System.Data.SqlClient.SqlDataReader"/>.</param>
/// <param name="output">The stream to output the CSV contents to.</param>
/// <param name="writeHeader">When true, a header is written using the column names.</param>
/// <param name="encoding">Optional parameter (defaulting to UTF8 without BOM) denoting how the data should be encoded.</param>
/// <param name="bufferSize">Optional parameter (defaulting to 1KB) which is used as a buffer for writing the data.</param>
/// <param name="closeOutput">Optional parameter which, when true, closes the <paramref name="output"/> <see cref="Stream"/> after we're doing writing.</param>
private static void WriteCsv(IDataReader reader, Stream output, bool writeHeader = true, Encoding encoding = null, int bufferSize = 1024, bool closeOutput = false)
{
    // If no encoding is provided, use the same one the StreamWriter defaults to.
    if (encoding == null)
        encoding = new UTF8Encoding(false, true);

    // Create a new writer to our CSV file.
    using (var writer = new StreamWriter(output, encoding, bufferSize, !closeOutput))
    {
        // This will create an enumerable with every integer between 0 and FieldCount-1.
        // Allows us to do a concise for loop and use String.Join to handle the comma placement.
        var indices = Enumerable.Range(0, reader.FieldCount);

        // Keep looping as long as their are rows returned by the reader.
        while (reader.Read())
        {
            // Write a header with the names of each column.
            if (writeHeader)
            {
                writer.WriteLine(String.Join(",", indices.Select(i => reader.GetName(i) ?? ("column" + i))));
                writeHeader = false;
            }

            // Write the value of each field by its string representation separated by a comma.
            writer.WriteLine(String.Join(",", indices.Select(i => (reader.IsDBNull(i) ? null : reader.GetString(i)) ?? "")));
        }
    }
}

这个函数可以让你对一些细节进行大量的控制,比如编码和你正在编写什么类型的流(你可以写入HTTP响应或常规文件,无所谓)。如果您要将更复杂的数据输出到CSV文件,我建议您在CSV“标准”上阅读this article

这位作家很天真 - 它只是写下它从IDataReader读取的原始数据。如果您的内容有换行符,回车符或逗号,则可能会混淆最终消耗程序输出的内容。我会编写一个CsvEncode函数,您可以将每个值提供给它,并根据上面文章中列出的规则对其进行正确编码。

这只是一个例子,而不是你应该实际使用的代码:

private static string CsvEncode(string value)
{
    // Handle commas within values.
    if (value.Contains(','))
    {
        // Strim so we get rid of beginning and trailing whitespaces we'd usually ignore.
        value = value.Trim();

        // If the value is already wrapped with quotation marks but has quotation marks within as well,
        if (value.StartsWith("\"") && value.EndsWith("\"") && value.IndexOf('\"', 1, value.Length-2) > 0)
            value = "\"" + value.Substring(1, value.Length - 2).Replace("\"", "\"\"") + "\"";
        else if (value.Contains("\"")) // Replace all quotations with two quotations, then wrap the final result.
            value = "\"" + value.Replace("\"", "\"\"") + "\"";
    }
    return value;
}

你只需更新WriteCsv所以当它写入行的值时,你调用CsvEncode,就像(只是一个例子):

// Write the value of each field by its string representation separated by a comma.
writer.WriteLine(String.Join(",", indices.Select(i => CsvEncode(reader.IsDBNull(i) ? "" : reader.GetString(i) ?? ""))));

只是要彻底,这就是你怎么称呼它:

using (var reader = command.ExecuteReader())
{
    if (!reader.HasRows)
        return; // Nothing to do.

    // You want it on the desktop? We'll put it on the desktop.
    var filePath = string.Format("{0}{1}exclusion_{2:MMddyyHHmmss}.csv",
        Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
        Path.PathSeparator,
        today);

    // Pass in the reader we got from executing the command. File.Create will replace any 
    // existing files. closeOutput is true because we do not keep a reference to the FileStream.
    WriteCsv(reader, File.Create(filePath), closeOutput: true);                
}