用C#将数据写入CSV文件
我正在尝试使用C#语言逐行写入一个csv
文件。 这是我的function
string first = reader[0].ToString(); string second=image.ToString(); string csv = string.Format("{0},{1}\n", first, second); File.WriteAllText(filePath, csv);
整个函数在一个循环内部运行,并且每一行都应该被写入到csv
文件中。 在我的情况下,下一行将覆盖现有的行,最后我只获得单个logging在最后一个csv文件。 我怎样才能在csv
文件中写出所有的行。
UPDATE
回到我天真的时候,我build议手动做这个(这是一个简单的问题的简单解决scheme),但是由于这个问题变得越来越stream行,我推荐使用一个库来执行所有的安全检查等等。
CSV比问题/答案所提出的要复杂得多。
原始答复
因为你已经有了一个循环,可以考虑这样做:
//before your loop var csv = new StringBuilder(); //in your loop var first = reader[0].ToString(); var second = image.ToString(); //Suggestion made by KyleMit var newLine = string.Format("{0},{1}", first, second); csv.AppendLine(newLine); //after your loop File.WriteAllText(filePath, csv.ToString());
或者是这个效果 我的推理是:你不需要写每个项目的文件,你只会打开一个stream,然后写入它。
你可以replace
File.WriteAllText(filePath, csv.ToString());
同
File.AppendAllText(filePath, csv.ToString());
如果你想保留以前版本的csv在同一个文件中
C#6
如果您正在使用c#6.0,那么您可以执行以下操作
var newLine = $"{first},{second}"
编辑
这里是一个问题的链接 ,解释了Environment.NewLine
作用
我强烈build议你去更繁琐的路线。 特别是如果您的文件大小。
using(var w = new StreamWriter(path)) { for( /* your loop */) { var first = yourFnToGetFirst(); var second = yourFnToGetSecond(); var line = string.Format("{0},{1}", first, second); w.WriteLine(line); w.Flush(); } }
File.AppendAllText()
打开一个新文件,写入内容然后closures文件。 打开文件比将数据写入打开的stream更耗费资源。 打开\closures循环内的文件将导致性能下降。
Johan提出的方法通过将所有输出存储在内存中然后写入一次来解决这个问题。 但是(在大文件的情况下)你的程序将会消耗大量的内存,甚至会因为OutOfMemoryException
而崩溃
我的解决scheme的另一个优点是可以通过在input数据中保存当前位置来实现暂停\恢复。
UPD。 放置在正确的地方
手动编写csv文件可能很困难,因为您的数据可能包含逗号和换行符。 我build议你改用现有的库。
这个问题提到了一些select。
C#中是否有CSV读取器/写入器库?
我使用了两个parsing解决scheme,因为它很容易维护
// Prepare the values var allLines = (from trade in proposedTrades select new object[] { trade.TradeType.ToString(), trade.AccountReference, trade.SecurityCodeType.ToString(), trade.SecurityCode, trade.ClientReference, trade.TradeCurrency, trade.AmountDenomination.ToString(), trade.Amount, trade.Units, trade.Percentage, trade.SettlementCurrency, trade.FOP, trade.ClientSettlementAccount, string.Format("\"{0}\"", trade.Notes), }).ToList(); // Build the file content var csv = new StringBuilder(); allLines.ForEach(line => { csv.AppendLine(string.Join(",", line)); }); File.WriteAllText(filePath, csv.ToString());
只需使用AppendAllText:
File.AppendAllText(filePath, csv);
AppendAllText唯一的缺点是当文件不存在时会抛出错误,所以必须检查
对不起,在阅读文档之前的金发时刻。 无论如何,如果文件存在,WriteAllText方法将覆盖之前写入文件的所有内容。
请注意,您当前的代码不使用正确的新行,例如在记事本中,您将看到所有这一行都是一条长长的行。 将代码更改为有适当的新行:
string csv = string.Format("{0},{1}{2}", first, image, Environment.NewLine);
而不是每次调用AppendAllText()
都应该考虑打开一次文件,然后写下整个内容:
var file = @"C:\myOutput.csv"; using (var stream = File.CreateText(file)) { for (int i = 0; i < reader.Count(); i++) { string first = reader[i].ToString(); string second = image.ToString(); string csvRow = string.Format("{0},{1}", first, second); stream.WriteLine(csvRow); } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data; using System.Configuration; using System.Data.SqlClient; public partial class CS : System.Web.UI.Page { protected void ExportCSV(object sender, EventArgs e) { string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString; using (SqlConnection con = new SqlConnection(constr)) { using (SqlCommand cmd = new SqlCommand("SELECT * FROM Customers")) { using (SqlDataAdapter sda = new SqlDataAdapter()) { cmd.Connection = con; sda.SelectCommand = cmd; using (DataTable dt = new DataTable()) { sda.Fill(dt); //Build the CSV file data as a Comma separated string. string csv = string.Empty; foreach (DataColumn column in dt.Columns) { //Add the Header row for CSV file. csv += column.ColumnName + ','; } //Add new line. csv += "\r\n"; foreach (DataRow row in dt.Rows) { foreach (DataColumn column in dt.Columns) { //Add the Data rows. csv += row[column.ColumnName].ToString().Replace(",", ";") + ','; } //Add new line. csv += "\r\n"; } //Download the CSV file. Response.Clear(); Response.Buffer = true; Response.AddHeader("content-disposition", "attachment;filename=SqlExport.csv"); Response.Charset = ""; Response.ContentType = "application/text"; Response.Output.Write(csv); Response.Flush(); Response.End(); } } } } } }
处理逗号
为了在使用string.Format(...)
时处理值内部的逗号,以下对我string.Format(...)
:
var newLine = string.Format("\"{0}\",\"{1}\",\"{2}\"", first, second, third ); csv.AppendLine(newLine);
所以把它和Johan的答案结合起来,看起来是这样的:
//before your loop var csv = new StringBuilder(); //in your loop var first = reader[0].ToString(); var second = image.ToString(); //Suggestion made by KyleMit var newLine = string.Format("\"{0}\",\"{1}\"", first, second); csv.AppendLine(newLine); //after your loop File.WriteAllText(filePath, csv.ToString());
正在返回CSV文件
如果你只是想返回文件,而不是写到一个位置,这是我如何完成它的一个例子:
从一个存储过程
public FileContentResults DownloadCSV() { // I have a stored procedure that queries the information I need SqlConnection thisConnection = new SqlConnection("Data Source=sv12sql;User ID=UI_Readonly;Password=SuperSecure;Initial Catalog=DB_Name;Integrated Security=false"); SqlCommand queryCommand = new SqlCommand("spc_GetInfoINeed", thisConnection); queryCommand.CommandType = CommandType.StoredProcedure; StringBuilder sbRtn = new StringBuilder(); // If you want headers for your file var header = string.Format("\"{0}\",\"{1}\",\"{2}\"", "Name", "Address", "Phone Number" ); sbRtn.AppendLine(header); // Open Database Connection thisConnection.Open(); using (SqlDataReader rdr = queryCommand.ExecuteReader()) { while (rdr.Read()) { // rdr["COLUMN NAME"].ToString(); var queryResults = string.Format("\"{0}\",\"{1}\",\"{2}\"", rdr["Name"].ToString(), rdr["Address"}.ToString(), rdr["Phone Number"].ToString() ); sbRtn.AppendLine(queryResults); } } thisConnection.Close(); return File(new System.Text.UTF8Encoding().GetBytes(sbRtn.ToString()), "text/csv", "FileName.csv"); }
从列表中
/* To help illustrate */ public static List<Person> list = new List<Person>(); /* To help illustrate */ public class Person { public string name; public string address; public string phoneNumber; } /* The important part */ public FileContentResults DownloadCSV() { StringBuilder sbRtn = new StringBuilder(); // If you want headers for your file var header = string.Format("\"{0}\",\"{1}\",\"{2}\"", "Name", "Address", "Phone Number" ); sbRtn.AppendLine(header); foreach (var item in list) { var listResults = string.Format("\"{0}\",\"{1}\",\"{2}\"", item.name, item.address, item.phoneNumber ); sbRtn.AppendLine(listResults); } } return File(new System.Text.UTF8Encoding().GetBytes(sbRtn.ToString()), "text/csv", "FileName.csv"); }
希望这是有帮助的。
可以使用图书馆,而不是重新发明轮子。 CsvHelper
非常适合创build和阅读CSV文件。 它的读写操作是基于stream的,因此也支持大量数据的操作。
你可以写下你的CSV文件。
using(var textWriter = new StreamWriter(@"C:\mypath\myfile.csv") { var writer = new CsvWriter(textWriter); writer.Configuration.Delimiter = ","; foreach (var item in list) { csv.WriteField( "a" ); csv.WriteField( 2 ); csv.WriteField( true ); csv.NextRecord(); } }
由于库正在使用reflection,它将采取任何types,并直接parsing它。
public class CsvRow { public string Column1 { get; set; } public bool Column2 { get; set; } public CsvRow(string column1, bool column2) { Column1 = column1; Column2 = column2; } } IEnumerable<CsvRow> rows = new [] { new CsvRow("value1", true), new CsvRow("value2", false) }; using(var textWriter = new StreamWriter(@"C:\mypath\myfile.csv") { var writer = new CsvWriter(textWriter); writer.Configuration.Delimiter = ","; writer.WriteRecords(rows); }
值1,真
值2,假
如果你想了解更多关于图书馆的configuration和可能性,你可以在这里做。
您可能只需添加换行符"\n\r"
。
这里是另一个开源库,可以很容易地创buildCSV文件,即Cinchoo ETL
List<dynamic> objs = new List<dynamic>(); dynamic rec1 = new ExpandoObject(); rec1.Id = 10; rec1.Name = @"Mark"; rec1.JoinedDate = new DateTime(2001, 2, 2); rec1.IsActive = true; rec1.Salary = new ChoCurrency(100000); objs.Add(rec1); dynamic rec2 = new ExpandoObject(); rec2.Id = 200; rec2.Name = "Tom"; rec2.JoinedDate = new DateTime(1990, 10, 23); rec2.IsActive = false; rec2.Salary = new ChoCurrency(150000); objs.Add(rec2); using (var parser = new ChoCSVWriter("emp.csv").WithFirstLineHeader()) { parser.Write(objs); }
欲了解更多信息,请阅读使用CodeProject文章。