How to write to separate columns in csv - c#

I have a html table which I am trying to write to a csv file. I have the rows seperated by a \n in my array and when I print it to the csv file everything works except one problem I'm having. I want each comma value to be printed in the next column. Unfortunately it is not doing that. My current code writes all the values from each row in the html table to the correct rows in the csv.
try
{
string filepath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
StreamWriter sw = new StreamWriter(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\spreadsheet.csv", true);
foreach (var i in valueArray)
{
if (i.ToString() == "\n")
{
sw.Write("\n");
}
else
{
{
sw.Write(i.ToString());
sw.Write("\t");//my failed attempt
}
}
}
sw.Flush();
sw.Close();
saveOK = true;
}
values in the array would look like : "first,second,third,fourth,fith,last,\n, first, ....,last,\n,"
in the csv it shows up as :
column 1 column 2
row1 :firstsecondthirdfourthfithlast
row2 :firstsecond....... last

foreach (var i in valueArray)
{
if (i.ToString() == "\n")
{
sw.Write(sw.NewLine);
}
else
{
sw.Write(i.ToString() + ",");
}
}

Related

Remove last (empty) entry from StringBuilder object, when exporting to CSV

I want to remove the last (empty) row of a StringBuilder Object
EDIT: The empty row is from the "AllowUserToAddRows" how can i skip it?
c# Forms application
dataGridView1 on form2
I want Export to CSV (separated by semicolon) [btw. it's just one column]
It Could happen, that a previously created CSV is parsed to the dataGridView again
I use a altered solution from here:
Exporting datagridview to csv file
my code
void SaveDataGridViewToCSV(string filename)
{
var sb = new StringBuilder();
var headers = dataGridView1.Columns.Cast<DataGridViewColumn>();
sb.AppendLine(string.Join(";", headers.Select(column => "" + column.HeaderText + ";").ToArray()));
foreach (DataGridViewRow row in dataGridView1.Rows)
{
var cells = row.Cells.Cast<DataGridViewCell>();
sb.AppendLine(string.Join(";", cells.Select(cell => "" + cell.Value + ";").ToArray()));
}
try
{
File.WriteAllText(filename, sb.ToString());
}
catch (Exception exceptionObject)
{
MessageBox.Show(exceptionObject.ToString());
}
}
The sb.ToString looks like this {Coumn;90;90;626;626;;}
The "real" StringBuilder Object as String is: {Coumn;\r\n90;\r\n90;\r\n626;\r\n626;\r\n;}
I want to remove the empty last row.
I tried to parse the stringbuilder to a string, and then remove last semicolon
but with no success (i have problem with the End Of Line.)
string s = sb.ToString();
while (s.EndsWith(";\r\n;") == true)
{
s.Substring(0, s.Length - 5);
}
I tried to remove last element of array, but StingBuilder is no array
I'm stuck.
As i found out the empty set is always exported to the csv.
It's from the ability that the user can input data to the dataGridView, and there is always a empty, active row.
if i disable dataGridView1.AllowUserToAddRows the empty row for userinput is not within the stringbuilder set of data.
void SaveDataGridViewToCSV(string filename)
{
var sb = new StringBuilder();
//SOLUTION disable AllowUserInput to avoid empty set saved to CSV
dataGridView1.AllowUserToAddRows = false;
var headers = dataGridView1.Columns.Cast<DataGridViewColumn>();
sb.AppendLine(string.Join(";", headers.Select(column => "" + column.HeaderText + ";").ToArray()));
foreach (DataGridViewRow row in dataGridView1.Rows)
{
var cells = row.Cells.Cast<DataGridViewCell>();
sb.AppendLine(string.Join(";", cells.Select(cell => "" + cell.Value + ";").ToArray()));
}
try
{
File.WriteAllText(filename, sb.ToString());
}
catch (Exception exceptionObject)
{
MessageBox.Show(exceptionObject.ToString());
}
}
thanks for help!

Exporting DataGrid to CSV without a GUI in WPF

I have an application that runs with and without a GUI depending on the user. I need it to export the DataGrid as a CSV file, heres the code:
// Copy contents of datagrid to clipboard, including header.
mainDataGrid.SelectAllCells();
mainDataGrid.ClipboardCopyMode = DataGridClipboardCopyMode.IncludeHeader;
ApplicationCommands.Copy.Execute(null, mainDataGrid);
string result = (string)Clipboard.GetData(DataFormats.CommaSeparatedValue);
This works fine with the GUI. The problem happens when I don't have a GUI, I think this is because the clipboard can't copy something that isn't there. Is there a different way to export it or is there a way to set the clipboards data instead of executing a copy command?
In order to "copy something that isn't there", you'll need to use the underlying data object that is your DataGrid's ItemsSource.
If your DataGrid's ItemsSource is a DataTable, this method, analogous to MosesTheHoly's, will return a CSV string, but in a simpler manner.
public string GetCSVFromDataTabe(DataTable datatable)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(string.Join(",", dt.Columns.ToList<DataColumn>().Select(column => column.ColumnName).ToList()) + "\n");
dataTable.Rows.ToList<DataRow>().ForEach(row => sb.Append(string.Join(",", row.ItemArray) + "\n"));
return stringBuilder.ToString();
}
That should do it. Fairly concise, in my opinion. Now, just write that string to whatever file you need.
Alright, the code could probably be shortened, but this is the way I did it. I created a function that takes in a datatable and returns a CSV string.
private void SaveToCSV() {
DataTable dt = new DataTable();
dt = ((DataView)mainDataGrid.ItemsSource).ToTable();
string result = WriteDataTable(dt);
// The File.Create().Close() is so it closes the filestream after it creates it.
if (!File.Exists(CSVFilePath)) {
File.Create(CSVFilePath).Close();
}
File.AppendAllText(CSVFilePath, result, UnicodeEncoding.UTF8);
}
private string WriteDataTable(DataTable dataTable) {
string output = "";
// Need to get the last column so I know when to add a new line instead of comma.
string lastColumnName = dataTable.Columns[dataTable.Columns.Count - 1].ColumnName;
// Get the headers from the datatable.
foreach (DataColumn column in dataTable.Columns) {
if (lastColumnName != column.ColumnName) {
output += (column.ColumnName.ToString() + ",");
}
else {
output += (column.ColumnName.ToString() + "\n");
}
}
// Get the actual data from the datatable.
foreach (DataRow row in dataTable.Rows) {
foreach (DataColumn column in dataTable.Columns) {
if (lastColumnName != column.ColumnName) {
output += (row[column].ToString() + ",");
}
else {
output += (row[column].ToString() + "\n");
}
}
}
return output;
}

C# excel color text

I'm currently using the below code to compare two csv files with each other. I can select a column in the file and it will compare the rows in that column, it then writes the incorrect and correct rows into another csv file. But now I want to change the color the text 'this row is not the same' so that it's more noticeable. How can I do this?
public void comparing(int selectedRow, string filenaname, string filename2)
{
List<string> lines = new List<string>();
List<string> lines2 = new List<string>();
try
{
StreamReader reader = new StreamReader(System.IO.File.OpenRead(filename));
StreamReader read = new StreamReader(System.IO.File.OpenRead(filename2));
List<string> lijnen = new List<string>();
string line;
string line2;
string differencesFile= #"C:\Users\Mylan\Desktop\differences.csv";
while ((line = reader.ReadLine()) != null && (line2 = read.ReadLine()) != null)
{
string[] split = line.Split(Convert.ToChar(csvSeperator));
string[] split2 = line2.Split(Convert.ToChar(csvSeperator));
if (split[selectedRow] != split2[selectedRow])
{
lijnen.Add("This row is not the same:, " + line);
}
else if(test == test2)
{
System.Windows.Forms.MessageBox.Show("The whole file is the same");
break;
}
else
{
lines.Add("This row is the same:, " + line);
}
}
System.IO.File.WriteAllLines(differencesFile, lines);
System.Diagnostics.Process.Start(differencesFile);
reader.Dispose();
read.Dispose();
}
catch
{
}
}
}
}
I think it's impossible to do what you want with CSV files. Excel reads only the values and separate these in columns, that's all.
If you want to create an Excel file directly by code, you need to use for example the Open XML :
https://msdn.microsoft.com/en-gb/library/office/bb448854.aspx
This is what I use to create, edit Excel files (and Powerpoint files too). It's a bit tricky at beginning but it's a solution...

Multiple CSV to one csv file with Multiple CSV sheets

I have few CSV file contains different data, I want to combine all this csv file into one ultimate CSV file which contains multiple sheets, under which this multiple csv are accommodated.
Till now my below code picks data from the directory and combines all CSV file into one big CSV file where it is appending the data which i do not want, instead I want multiple sheet in one file..
private void combineallcsv()
{
string txtConsolidated_OS_CSV = "C:\\NWDLS\\new";
if (txtConsolidated_OS_CSV != "")
{
int counter = 0;
string[] files = (Directory.GetFiles(txtConsolidated_OS_CSV.Trim()));
foreach (var file in files)
{
StringBuilder sb = new StringBuilder();
string filename = Path.GetFileNameWithoutExtension(file);
if (file.EndsWith(".csv"))
{
string[] rows = File.ReadAllLines(file);
for (int i = 0; i < rows.Length; i++)
{
if (i == 0)
{
if (counter == 0)
{
sb.Append(rows[i] + "\n");
counter++;
}
}
else
{
sb.Append(rows[i] + "\n");
}
}
}
string csvfile = txtConsolidated_OS_CSV + "\\Merged_OS.csv";
if (File.Exists(csvfile))
{
File.AppendAllText(csvfile, sb.ToString());
sb.Clear();
}
else
{
File.WriteAllText(csvfile, sb.ToString());
sb.Clear();
}
//using (StreamWriter writer = new StreamWriter(csvfile, true))
//{
// writer.Write(sb.ToString());
// writer.Dispose();
// writer.Close();
//}
}
counter = 0;
}
}
There's not such thing as "sheets" in CSV files. CSV files are just lines of text where fields are separated by some defined character. That's all.
You can use VSTO office interop or ADO.NET drivers to create "real" Excel sheets.

Append data to a .csv File using C#

The following code writes the data and is working fine, but I want to add more than one client (maybe 10) in the .csv file. How can I achieve this. Thanks in advance.
private void createFileButton_Click(object sender, EventArgs e)
{
string newFileName = "C:\\client_20100913.csv";
string clientDetails = clientNameTextBox.Text + "," + mIDTextBox.Text + "," + billToTextBox.Text;
//Header of the .csv File
string clientHeader = "Client Name(ie. Billto_desc)" + "," + "Mid_id,billing number(ie billto_id)" + "," + "business unit id" + Environment.NewLine;
File.WriteAllText(newFileName, clientHeader);
File.AppendAllText(newFileName, clientDetails);
MessageBox.Show("Client Added", "Added", MessageBoxButtons.OK);
}
If you want to append the client information to an existing file, how about:
string newFileName = "C:\\client_20100913.csv";
string clientDetails = clientNameTextBox.Text + "," + mIDTextBox.Text + "," + billToTextBox.Text;
if (!File.Exists(newFileName))
{
string clientHeader = "Client Name(ie. Billto_desc)" + "," + "Mid_id,billing number(ie billto_id)" + "," + "business unit id" + Environment.NewLine;
File.WriteAllText(newFileName, clientHeader);
}
File.AppendAllText(newFileName, clientDetails);
This way the header line is only written the first time, when the file is created.
Although it would probably be even nicer to provide a list-detail view that lets you view all clients, add and remove clients, select a client to edit details, and save the complete file with all clients.
It looks to me like you want a new client to be added every time you click the button.
If that's the case, the reason why it doesn't work currently is that the file is being cleared by the line
File.WriteAllText(newFileName, clientHeader);
The simplest change would be to check if the file exists before writing over it:
if (!File.Exists(newFileName))
{
//Header of the .csv File
string clientHeader = "Client Name(ie. Billto_desc)" + "," + "Mid_id,billing number(ie billto_id)" + "," + "business unit id" + Environment.NewLine;
File.WriteAllText(newFileName, clientHeader);
}
Although you could use other strategies, such as creating the file on startup of the application and keeping it open (using something like a StreamWriter). You would then close the writer when your application exited. This would pretty much guarantee that the file couldn't be messed with while your application is open.
You might want to do this because there is a race condition in that code - after you check the file exists, and before you write to the file, a user could delete it. Keeping the file open helps to avoid this, but you may or may not want to do it.
The underlying problem here seems to be where you're getting the data from to append to your CSV file. Your example code looks like it gets the various pieces of data from text boxes on the page, so if you want multiple clients, are they all going to have their data on the screen in text boxes? My instinct is probably not.
It sounds to me like you should be handling this client data using a class of some sort (perhaps persisted in a database) and then implement a method in the class called something like void AppendToCSV(string filename), which appends that client data to the CSV file. Then you can loop over your client objects, appending each one in turn.
How you produce/store your client objects, in relation to the text boxes you have on the screen, depends on what your app is trying to achieve.
I know this has been answered but there is what i did to create a "log" of subscribers. This uses reflection to get the properties and values of the object. Hope this helps someone in the future.
internal static bool UpdateSubscriberList(MailingListEmail subscriber)
{
PropertyInfo[] propertyinfo;
propertyinfo = typeof(MailingListEmail).GetProperties();
var values = string.Empty;
try
{
string fileName = #"C:\Development\test.csv";
if (!File.Exists(fileName))
{
var header = string.Empty;
foreach (var prop in propertyinfo)
{
if (string.IsNullOrEmpty(header))
header += prop.Name;
else
header = string.Format("{0},{1}", header, prop.Name);
}
header = string.Format("{0},{1}", header, "CreatedDate");
header += Environment.NewLine;
File.WriteAllText(fileName, header);
}
foreach (var prop in propertyinfo)
{
var value = prop.GetValue(subscriber, null);
if (string.IsNullOrEmpty(values))
values += value;
else
values = string.Format("{0},{1}", values, value);
}
values = string.Format("{0},{1}", values, DateTime.Now.ToShortDateString());
values += Environment.NewLine;
File.AppendAllText(fileName, values);
}
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
return false;
}
return true;
}
here is what i have done, and it works for me perfectly :
first you need to creat DataTable from your listview, or just put data from textboxes:
`public Boolean PreparCVS(string DateOne, string DataTwo)
{
try
{
// Create the `DataTable` structure according to your data source
DataTable table = new DataTable();
table.Columns.Add("HeaderOne", typeof(string));
table.Columns.Add("HeaderTwo", typeof(String));
// Iterate through data source object and fill the table
table.Rows.Add(HeaderOne, HeaderTwo);
//Creat CSV File
CreateCSVFile(table, sCsvFilePath);
return true;
}
catch (Exception ex)
{
throw new System.Exception(ex.Message);
}
}`
once dataTable is created you can generate CSV file by this method :
in the streamwriter constructor you must specify in the second parameter True, by this, you can append data to you existing .csv file :
public void CreateCSVFile(DataTable dt, string strFilePath)
{
StreamWriter sw = new StreamWriter(strFilePath, true);
int iColCount = dt.Columns.Count;
for (int i = 0; i < iColCount; i++)
{
sw.Write(dt.Columns[i]);
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
foreach (DataRow dr in dt.Rows)
{
for (int i = 0; i < iColCount; i++)
{
if (!Convert.IsDBNull(dr[i]))
{
sw.Write(dr[i].ToString());
}
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
}
sw.Close();
}
// At first read all the data from your first CSV
StreamReader oStreamReader = new StreamReader(#"d:\test\SourceFile.csv");
string recordsFromFirstFile = oStreamReader.ReadToEnd();
oStreamReader.Close();
// Now read the new records from your another csv file
oStreamReader = new StreamReader(#"d:\test\DestinationFile.csv");
string recordsFromSecondFile = oStreamReader.ReadToEnd();
oStreamReader.Close();
oStreamReader.Dispose();
// Here Records from second file will also contain column headers so we need to truncate them using Substring() method
recordsFromSecondFile = recordsFromSecondFile.Substring(recordsFromSecondFile.IndexOf('\n') + 1);
// Now merge the records either in SourceFile.csv or in Targetfile.csv or as per your required file
StreamWriter oStreamWriter= new StreamWriter(#"d:\testdata\TargetFile.csv");
oStreamWriter.Write(recordsFromFirstFile + recordsFromSecondFile);
oStreamWriter.Close();
oStreamWriter.Dispose();
Happy Coding.....
c#csv
using CsvHelper;
public void WriteDataToCsv(MsgEnvironmentData[] data, string csvPath)
{
if (!File.Exists(csvPath))
{
using (var writer = new StreamWriter(csvPath))
using (var csvWriter = new CsvWriter(writer,firstConfiguration))
{
csvWriter.WriteHeader<MsgEnvironmentData>();
csvWriter.NextRecord();
csvWriter.WriteRecords(data);
}
}
else
{
using (var stream = new FileStream(csvPath, FileMode.Append))
using (var writer = new StreamWriter(stream))
using (var csvWriter = new CsvWriter(writer, secondConfiguration))
{
csvWriter.WriteRecords(data);
}
}
}
Jeramy's answer writing the contents on last cell and from their horizontally in a row in csv file. I mixed and matched his solution with answer given here. I know this questions been asked long before but for the ones who doing research I'm posting the answer here.
string newFileName = #"C:\.NET\test.csv"; //filepath
var csv = new StringBuilder();
string clientDetails = "content1,content2,content3" + Environment.NewLine;
csv.Append(clientDetails);
File.AppendAllText(newFileName, csv.ToString());
I use this simple piece of code to append data to an existing CSV file:
string[] data = { "John", "Doe", "25" };
string csvFilePath = "example.csv";
// Open the file for writing
using (StreamWriter writer = File.AppendText(csvFilePath))
{
// Write the data row
writer.WriteLine(string.Join(",", data));
}

Categories

Resources