Запись данных в CSV файл в С#
Я пытаюсь записать в файл csv
строка за строкой, используя язык С#. Вот моя функция
string first = reader[0].ToString();
string second=image.ToString();
string csv = string.Format("{0},{1}\n", first, second);
File.WriteAllText(filePath, csv);
Вся функция выполняется внутри цикла, и каждая строка должна быть записана в файл csv
. В моем случае следующая строка перезаписывает существующую строку, и в конце я получаю единственную запись в CSV файле, которая является последней. Как я могу записать все строки в csv
файл?
Ответы
Ответ 1
ОБНОВИТЬ
Еще в наивные времена я предлагал делать это вручную (это было простое решение простого вопроса), однако из-за того, что это становилось все более и более популярным, я бы рекомендовал использовать библиотеку 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 в том же файле
С# 6
Если вы используете С# 6.0, то вы можете сделать следующее
var newLine = $"{first},{second}"
РЕДАКТИРОВАТЬ
Вот ссылка на вопрос, который объясняет, что делает Environment.NewLine
Ответ 2
Я очень рекомендую вам пойти на более утомительный маршрут. Особенно, если размер вашего файла большой.
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
Еще одно преимущество моего решения заключается в том, что вы можете реализовать приостановку\возобновление, сохраняя текущую позицию во входных данных.
обн. Размещено в нужном месте
Ответ 3
Написание файлов csv вручную может быть затруднено, потому что ваши данные могут содержать запятые и символы новой строки. Вместо этого я предлагаю вам использовать существующую библиотеку.
В этом вопросе упоминаются несколько вариантов.
Есть ли в С# библиотеки чтения/записи CSV?
Ответ 4
Я использую два решения синтаксического анализа, поскольку их очень легко поддерживать
// 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());
Ответ 5
Вместо этого просто используйте AppendAllText:
File.AppendAllText(filePath, csv);
Единственный недостаток AppendAllText заключается в том, что он будет вызывать ошибку, если файл не существует, поэтому это нужно проверить
Извините, светлый момент перед чтением документации. В любом случае метод WriteAllText перезаписывает все, что было ранее записано в файле, если файл существует.
Обратите внимание, что ваш текущий код не использует правильные новые строки, например, в "Блокноте" вы увидите все как одну длинную строку. Измените код на это, чтобы иметь соответствующие новые строки:
string csv = string.Format("{0},{1}{2}", first, image, Environment.NewLine);
Ответ 6
Вместо того чтобы вызывать каждый раз 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);
}
}
Ответ 7
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();
}
}
}
}
}
}
Ответ 8
Вместо изобретения колеса можно использовать библиотеку. 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, правда,
значение2, ложь
Если вы хотите узнать больше о конфигурации и возможностях библиотек, вы можете сделать это здесь.
Ответ 9
Обработка запятых
Для обработки запятых внутри значений при использовании 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");
}
Из списка
/* 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");
}
Надеюсь, это поможет.
Ответ 10
Вам просто нужно добавить фид строки "\n\r"
.
Ответ 11
Вот еще одна библиотека с открытым исходным кодом для легкого создания файла 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 об использовании.
Ответ 12
Это простое руководство по созданию CSV файлов с использованием С#, которое вы сможете редактировать и расширять в соответствии со своими потребностями.
Сначала вам нужно создать новое консольное приложение Visual Studio С#, для этого нужно выполнить следующие шаги.
Пример кода создаст 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);
}
}
}
Ответ 13
Один простой способ избавиться от проблемы с перезаписью - использовать 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);
}
}
Ответ 14
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
}
}
}