我有一个存储过程,它将返回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
我从未使用过文件创建功能,现在它可以保存到我的桌面上。是容易做的事情吗?
答案 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.IDataReader
(System.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);
}