Запись данных в CSV-файл на C#
Я пытаюсь написать в csv файл строка за строкой с использованием языка C#. Вот моя функция
string first = reader[0].ToString();
string second=image.ToString();
string csv = string.Format("{0},{1}n", first, second);
File.WriteAllText(filePath, csv);
вся функция работает внутри цикла, и каждая строка должна быть записана в . В моем случае следующая строка перезаписывает существующую строку, и в конце концов я получаю только одну запись в файле csv, который является последним. Как я могу написать все строки в .
14 ответов:
обновление
еще в мои наивные дни я предложил сделать это вручную (это было простое решение простого вопроса), однако из-за этого становится все более популярным, я бы рекомендовал использовать библиотеку CsvHelper что делает все проверки безопасности и т. д.
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());или что-то в этом роде. Мои рассуждения таковы: вам не нужно будет писать в файл для каждого элемента, вы будете только открывать поток один раз, а затем писать в него.
вы можете заменить
File.WriteAllText(filePath, csv.ToString());С
File.AppendAllText(filePath, csv.ToString());если вы хотите сохранить предыдущие версии csv в том же файле
C# 6
если вы используете C# 6.0, то вы можете сделать после
var newLine = $"{first},{second}"EDIT
здесь ссылке на вопрос, который объясняет, что
Environment.NewLineтут
я настоятельно рекомендую вам пойти более утомительным маршрутом. Особенно если размер файла большой.
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()открывает новый файл, записывает содержимое и затем закрывает файл. Открытие файлов-это гораздо более ресурсоемкая операция, чем запись данных в открытый поток. Открытие\закрытие файла внутри цикла приведет к снижению производительности.подход, предложенный Йоханом, решает эту проблему, сохраняя все выходные данные в памяти, а затем записывая их один раз. Однако (в случае больших файлов), программа будет потреблять большое количество оперативной памяти и даже рухнуть с
OutOfMemoryExceptionеще одним преимуществом моего решения является то, что вы можете реализовать приостановку\возобновление, сохранив текущую позицию во входных данных.
upd. Размещено с помощью в нужном месте
написание csv-файлов вручную может быть затруднено, потому что ваши данные могут содержать запятые и новые строки. Я предлагаю вам использовать существующую библиотеку вместо этого.
в этом вопросе упоминается несколько вариантов.
Я использую два разбора решение, как это очень легко поддерживать
// 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(); } } } } } }
вместо изобретения колеса можно использовать библиотеку.
CsvHelperотлично подходит для создания и чтения CSV-файлов. Это операции чтения и записи основаны на потоке и поэтому также поддерживают операции с большим количеством данных.
вы можете написать свой csv следующим образом.
using(var textWriter = new StreamWriter(@"C:\mypath\myfile.csv")) { var writer = new CsvWriter(textWriter); writer.Configuration.Delimiter = ","; foreach (var item in list) { writer.WriteField( "a" ); writer.WriteField( 2 ); writer.WriteField( true ); writer.NextRecord(); } }
поскольку библиотека использует отражение, она будет принимать любой тип и анализировать его напрямую.
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); }value1, true
value2, false
Если вы хотите узнать больше о конфигурациях и возможностях библиотек, вы можете сделать это здесь.
Обращение Запятыми
для обработки разделителей внутри значений при использовании
string.Format(...), для меня сработало следующее:var newLine = string.Format("\"{0}\",\"{1}\",\"{2}\"", first, second, third ); csv.AppendLine(newLine);поэтому, чтобы объединить его с ответом Йохана, это будет выглядеть так:
//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"); }от a Список
/* 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"); }надеюсь, это полезно.
вот еще одна библиотека с открытым исходным кодом для создания CSV-файла легко, 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 статья об использовании.
Это простой учебник по созданию csv-файлов с помощью C#, которые вы сможете редактировать и расширять, чтобы соответствовать вашим собственным потребностям.
сначала вам нужно создать новое консольное приложение Visual Studio C#, для этого необходимо выполнить следующие действия.
пример кода создаст csv-файл с именем MyTest.csv в указанном расположении. Содержимое файла должно быть 3 именованных столбца с текстом в первых 3 строки.
https://tidbytez.com/2018/02/06/how-to-create-a-csv-file-with-c/
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; namespace CreateCsv { class Program { static void Main() { // Set the path and filename variable "path", filename being MyTest.csv in this example. // Change SomeGuy for your username. string path = @"C:\Users\SomeGuy\Desktop\MyTest.csv"; // Set the variable "delimiter" to ", ". string delimiter = ", "; // This text is added only once to the file. if (!File.Exists(path)) { // Create a file to write to. string createText = "Column 1 Name" + delimiter + "Column 2 Name" + delimiter + "Column 3 Name" + delimiter + Environment.NewLine; File.WriteAllText(path, createText); } // This text is always added, making the file longer over time // if it is not deleted. string appendText = "This is text for Column 1" + delimiter + "This is text for Column 2" + delimiter + "This is text for Column 3" + delimiter + Environment.NewLine; File.AppendAllText(path, appendText); // Open the file to read from. string readText = File.ReadAllText(path); Console.WriteLine(readText); } } }
один простой способ избавиться от проблемы перезаписи-использовать
File.AppendTextдобавить строку в конец файлаvoid Main() { using (System.IO.StreamWriter sw = System.IO.File.AppendText("file.txt")) { string first = reader[0].ToString(); string second=image.ToString(); string csv = string.Format("{0},{1}\n", first, second); sw.WriteLine(csv); } }
public void UlozCSV() { using (StreamWriter pisar = new StreamWriter("zbozi.csv", false, Encoding.Default)) {// u ukládání nezapomenout - za názvem je FALSE pisar.WriteLine(hlavicka); //první řešíme hlavičku csv a následně vypisujeme jednotlivé reproduktory foreach (Reproduktor item in list) { pisar.WriteLine(item.ObjektNaCSVRadek()); //metoda která vypíše podle své třídy } } }
Comments