Write in next column in csv file c# - c#

I have two list every list have different data i want to add the lists data to csv file my problem how to write in the next column.
The two list is dl, xl i want to write xl in column and dl in another column
this my code
using (StreamWriter sw = File.CreateText("list.csv"))
{
for (int i = 0; i < dl.Count; i++)
{
// the two list have the same count
sw.WriteLine(dl[i]);
sw.WriteLine(xl[i]); // i want to write this in another column
}
}

You are not writing an Excel file. You are writing a CSV file which is compatible with Excel. CSV stands for "Comma separated values," meaning that you should use the comma as a column separator.
So... change this:
sw.WriteLine(dl[i]);
sw.WriteLine(xl[i]); // i want to write this in another column
To this:
var line = String.Format("{0},{1}", dl[i], xl[i]);
sw.WriteLine(line);

As already explained in other answer, CSV files are a special type of text file, where we have multiple records of data, one row per line. (Like a table row in RDBMS tables). Now, each line/row can have multiple data-part(s) or columns or data (like data column in a table row), separated by comma ','.
Basically a CSV file represents a table of data. It is not an Excel file, but can be open with MS Excel and edited easily.
So, a typical csv data file will look like
EmployeeId,Name,Dept
1,John,CSharp
2,Eric,Compiler
So, to make a new data-row, you just write the contents in a new line. And to mark the columns, you separate them with comma. As asked by op, if each value of dl and xl are to be created as columns in the csv file, they should be written in a line separated by comma. This can be achieved by changing the code inside for loop to
sw.WriteLine(dl[i] + "," + xl[i]);
Here + is used to concatenate three string values, but for more stings or even for this, it can be done in a cleaner way using
string.Format("{0},{1}", dl[i], xl[i]);

to those who are searching to write in two column just add ;
string.Format("{0};{1}", dl[i], xl[i]);

I found the easiest way to do it was:
using (StreamWriter sw = File.CreateText("newfile.csv"))
{
for (int i = 0; i < threshhld; i++)
{
//writing two columns right next to eachother
sw.WriteLine(dl[i] + "," + xl[i]);
}
}

Related

Unable to create different columns in CSV

I try to create a csv file in c#. First I wrote a little piece of code to test. I saw on that post that the "," character is use to create different columns but it doesn't work for me.
I searched on different topic but all answer are something like String.Format("{0},{1}", first, second);
My code :
String first = "Test name";
String second = "Value";
String newLine = String.Format("{0},{1}", first, second);
csv.AppendLine(newLine);
for (int i = 0; i < 3; i++)
{
first = "Test_" + i;
second = i.ToString();
newLine = String.Format("{0},{1}", first, second);
csv.AppendLine(newLine);
}
System.IO.File.WriteAllText(path, csv.ToString());
This create rightly the lines but all in column 1
Assuming csv to be a StringBuilder, this should create the file
Test name,Value
Test_0,0
Test_1,1
Test_2,2
which is a valid CSV file with two columns and three rows (and headers).
Are you by any chance using a non-English locale (specifically, one that uses the comma as a decimal separator) and trying to load the CSV in Excel? In that case Excel assumes ; as the field separator instead of ,. You can split the data with custom settings if needed (I believe the feature is called “Text to fields”, or “Text to columns” on the Data tab in the ribbon).

How to get rid of empty lines when using StreamWriter

I'm trying to write a text file, from a datatable, text file which later on will be imported by some other application, therefor I need to have no empty lines in the exported file (at the end or between).
I used the following code:
DataTable table = FisierSoldata.dtSoldata;
var result = new StringBuilder();
foreach (DataRow row in table.Rows)
{
for (int i = 0; i < table.Columns.Count; i++)
{
result.Append(row[i].ToString());
result.Append(i == table.Columns.Count - 1 ? "\n" : " ");
}
result.AppendLine();
}
StreamWriter objWriter = new StreamWriter(filePath, false);
objWriter.WriteLine(result.ToString());
objWriter.Close();
My datatable has 26 records and when the file is generated, it has one dataline followed by one empty line and another dataline and so on and at the end after the last dataline it has 3 empty lines.
How can I modify the code in order to have only datalines without the empty one between data and without the last 3 empty ones?
Regards,
LE:I've found a workaround, by reading some similar thread, but the solution was to use both streamwriter and streamreader in order to remove the unneeded data (empty lines) from the file which will be generated. But I wanted to know if there's a way of getting the file as needed from the start.
Why not using File.WriteAllLines, it's using a StreamWriter behind the scenes but allows simpler code:
var fileLines = table.AsEnumerable()
.Select(row => String.Join(" ", row.ItemArray))
.Where(line => !String.IsNullOrWhiteSpace(line));
File.WriteAllLines(filePath, fileLines);
But you really want to use a space as column delimiter? That's very error-prone. It will fail as soon as one field value contains a space.
I would try to avoid to add the empty lines to the Stringbuild. The Stringclass should give appropriate functions, maybe something like this:
String stringToTestIsEmpty = row[i].ToString();
//Check if it is not an empty line
if( ! String.IsNullOrWhiteSpace(stringToTestIsEmpty ))
{
resutl.Append(stringToTestIsEmpty);
}

Read a CSV file and writer into a file without " " using C#

I am trying to read a CSV file and stored all the values in the single list.CSV file contains credentials as uid(userid) and pass(password) and separated by','I have successfully read all the lines and write it in the file.but when it writes in the file, it write the value in between " "(double quotes) like as("abcdefgh3 12345678")what i want actually to remove this "" double quotes sign when i write it in to the files.i am pasting my code here:
static void Main(string[] args)
{
var reader = new StreamReader(File.OpenRead(#"C:\Desktop\userid1.csv"));
List<string> listA = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(',');
listA.Add(values[0]);
listA.Add(values[1]);
}
foreach (string a in listA)
{
TextWriter tr = new StreamWriter(#"E:\newfiless",true);
tr.Write(a);
tr.Write(tr.NewLine);
tr.Close();
}
}
and the resulted output is like this:
"uid
pass"
"Martin123
123456789"
"Damian
91644"
but i want in this form:
uid
pass
Martin123
123456789
Damian
91644
Thanking you all in advance.
The original file clearly has quotes, which makes it a CSV file with only one colum and in that column there are two values. Not usual, but it happens.
To actually remove quotes you can use Trim, TrimEnd or TrimStart.
You can remove the quotes while reading, or while writing, in this case it doesn't really matter.
var line = reader.ReadLine().Trim('"');
This will remove the quotes while reading. Note that this assumes the CSV is of this "broken" variant.
tr.WriteLine(a.Trim('"'));
This will handle it on write. This will work even if the file is "correct" CSV having two columns and values in quotes.
Note that you can use WriteLine to add the newline, no need for two Write calls.
Also as others have commented, don't create a TextWriter in the loop for every value, create it once.
using (TextWriter tr = new StreamWriter(#"E:\newfiless"))
{
foreach (string a in listA)
{
tr.WriteLine(a.Trim('"'));
}
}
The using will take care of closing the file and other possible resources even if there is an exception.
I assume that all you need to read the input file, strip out all starting/ending quotation marks, then split by comma and write it all to another file. You can actually accomplish it in a one-liner using SelectMany, which will produce a "flat" collection:
File.WriteAllLines(
#"c:\temp\output.txt",
File
.ReadAllLines(#"c:\temp\input.csv")
.SelectMany(line => line.Trim('"').Split(','))
);
It's not quite clear from your example where quotation marks are located in the file. For a typical .CSV file some comma-separated field might be wrapped in quotation marks to allow commas to be a part of the content. If it's the case, then parsing will be more complex.
You can use
tr.Write(a.Substring(1, line.Length - 2));
Edited
Please use Trim
tr.Write(a.TrimEnd('"').TrimStart('"'));

C# so I need to split out a string, I think

so I have this application that I have inherited from someone that is long gone. The gist of the application is that it reads in a .cvs file that has about 5800 lines in it, copies it over to another .cvs, which it creates new each time, after striping out a few things , #, ', &. Well everything works great, or it has until about a month ago. so I started checking into it, and what I have found so far is that there are about 131 items missing from the spreadsheet. Now I read someplace that the maximun amount of data a string can hold is over 1,000,000,000 chars, and my spreadsheet is way under that, around 800,000 chars, but the only thing I can think is doing it is the string object.
So anyway, here is the code in question, this piece appears
to both read in from the existing field, and output to the new file:
StreamReader s = new StreamReader(File);
//Read the rest of the data in the file.
string AllData = s.ReadToEnd();
//Split off each row at the Carriage Return/Line Feed
//Default line ending in most windows exports.
//You may have to edit this to match your particular file.
//This will work for Excel, Access, etc. default exports.
string[] rows = AllData.Split("\r\n".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
//Now add each row to the DataSet
foreach (string r in rows)
{
//Split the row at the delimiter.
string[] items = r.Split(delimiter.ToCharArray());
//Add the item
result.Rows.Add(items);
}
If anyone can help me I would really appreciate it. I either need to figure out how to split the data better, or I need to figure out why it is cutting out the last 131 lines from the existing excel file to the new excel file.
One easier way to do this, since you're using "\r\n" for lines, would be to just use the built-in line reading method: File.ReadLines(path)
foreach(var line in File.ReadLines(path))
{
var items = line.Split(',');
result.Rows.Add(items);
}
You may want to check out the TextFieldParser class, which is part of the Microsoft.VisualBasic.FileIO namespace (yes, you can use this with C# code)
Something along the lines of:
using(var reader = new TextFieldParser("c:\\path\\to\\file"))
{
//configure for a delimited file
reader.TextFieldType = FieldType.Delimited;
//configure the delimiter character (comma)
reader.Delimiters = new[] { "," };
while(!reader.EndOfData)
{
string[] row = reader.ReadFields();
//do stuff
}
}
This class can help with some of the issues of splitting a line into its fields, when the field may contain the delimiter.

How to format and read CSV file?

Here is just an example of the data I need to format.
The first column is simple, the problem the second column.
What would be the best approach to format multiple data fields in one column?
How to parse this data?
Important*: The second column needs to contain multiple values, like in an example below
Name Details
Alex Age:25
Height:6
Hair:Brown
Eyes:Hazel
A csv should probably look like this:
Name,Age,Height,Hair,Eyes
Alex,25,6,Brown,Hazel
Each cell should be separated by exactly one comma from its neighbor.
You can reformat it as such by using a simple regex which replaces certain newline and non-newline whitespace with commas (you can easily find each block because it has values in both columns).
A CSV file is normally defined using commas as field separators and CR for a row separator. You are using CR within your second column, this will cause problems. You'll need to reformat your second column to use some other form of separator between multiple values. A common alternate separator is the | (pipe) character.
Your format would then look like:
Alex,Age:25|Height:6|Hair:Brown|Eyes:Hazel
In your parsing, you would first parse the comma separated fields (which would return two values), and then parse the second field as pipe separated.
This is an interesting one - it can be quite difficult to parse specific format files which is why people often write specific classes to deal with them. More conventional file formats like CSV, or other delimited formats are [more] easy to read because they are formatted in a similar way.
A problem like the above can be addressed in the following way:
1) What should the output look like?
In your instance, and this is just a guess, but I believe you are aiming for the following:
Name, Age, Height, Hair, Eyes
Alex, 25, 6, Brown, Hazel
In which case, you have to parse out this information based on the structure above. If it's repeated blocks of text like the above then we can say the following:
a. Every person is in a block starting with Name Details
b. The name value is the first text after Details, with the other columns being delimited in the format Column:Value
However, you might also have sections with addtional attributes, or attributes that are missing if the original input was optional, so tracking the column and ordinal would be useful too.
So one approach might look like the following:
public void ParseFile(){
String currentLine;
bool newSection = false;
//Store the column names and ordinal position here.
List<String> nameOrdinals = new List<String>();
nameOrdinals.Add("Name"); //IndexOf == 0
Dictionary<Int32, List<String>> nameValues = new Dictionary<Int32 ,List<string>>(); //Use this to store each person's details
Int32 rowNumber = 0;
using (TextReader reader = File.OpenText("D:\\temp\\test.txt"))
{
while ((currentLine = reader.ReadLine()) != null) //This will read the file one row at a time until there are no more rows to read
{
string[] lineSegments = currentLine.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
if (lineSegments.Length == 2 && String.Compare(lineSegments[0], "Name", StringComparison.InvariantCultureIgnoreCase) == 0
&& String.Compare(lineSegments[1], "Details", StringComparison.InvariantCultureIgnoreCase) == 0) //Looking for a Name Details Line - Start of a new section
{
rowNumber++;
newSection = true;
continue;
}
if (newSection && lineSegments.Length > 1) //We can start adding a new person's details - we know that
{
nameValues.Add(rowNumber, new List<String>());
nameValues[rowNumber].Insert(nameOrdinals.IndexOf("Name"), lineSegments[0]);
//Get the first column:value item
ParseColonSeparatedItem(lineSegments[1], nameOrdinals, nameValues, rowNumber);
newSection = false;
continue;
}
if (lineSegments.Length > 0 && lineSegments[0] != String.Empty) //Ignore empty lines
{
ParseColonSeparatedItem(lineSegments[0], nameOrdinals, nameValues, rowNumber);
}
}
}
//At this point we should have collected a big list of items. We can then write out the CSV. We can use a StringBuilder for now, although your requirements will
//be dependent upon how big the source files are.
//Write out the columns
StringBuilder builder = new StringBuilder();
for (int i = 0; i < nameOrdinals.Count; i++)
{
if(i == nameOrdinals.Count - 1)
{
builder.Append(nameOrdinals[i]);
}
else
{
builder.AppendFormat("{0},", nameOrdinals[i]);
}
}
builder.Append(Environment.NewLine);
foreach (int key in nameValues.Keys)
{
List<String> values = nameValues[key];
for (int i = 0; i < values.Count; i++)
{
if (i == values.Count - 1)
{
builder.Append(values[i]);
}
else
{
builder.AppendFormat("{0},", values[i]);
}
}
builder.Append(Environment.NewLine);
}
//At this point you now have a StringBuilder containing the CSV data you can write to a file or similar
}
private void ParseColonSeparatedItem(string textToSeparate, List<String> columns, Dictionary<Int32, List<String>> outputStorage, int outputKey)
{
if (String.IsNullOrWhiteSpace(textToSeparate)) { return; }
string[] colVals = textToSeparate.Split(new[] { ":" }, StringSplitOptions.RemoveEmptyEntries);
List<String> outputValues = outputStorage[outputKey];
if (!columns.Contains(colVals[0]))
{
//Add the column to the list of expected columns. The index of the column determines it's index in the output
columns.Add(colVals[0]);
}
if (outputValues.Count < columns.Count)
{
outputValues.Add(colVals[1]);
}
else
{
outputStorage[outputKey].Insert(columns.IndexOf(colVals[0]), colVals[1]); //We append the value to the list at the place where the column index expects it to be. That way we can miss values in certain sections yet still have the expected output
}
}
After running this against your file, the string builder contains:
"Name,Age,Height,Hair,Eyes\r\nAlex,25,6,Brown,Hazel\r\n"
Which matches the above (\r\n is effectively the Windows new line marker)
This approach demonstrates how a custom parser might work - it's purposefully over verbose as there is plenty of refactoring that could take place here, and is just an example.
Improvements would include:
1) This function assumes there are no spaces in the actual text items themselves. This is a pretty big assumption and, if wrong, would require a different approach to parsing out the line segments. However, this only needs to change in one place - as you read a line at a time, you could apply a reg ex, or just read in characters and assume that everything after the first "column:" section is a value, for example.
2) No exception handling
3) Text output is not quoted. You could test each value to see if it's a date or number - if not, wrap it in quotes as then other programs (like Excel) will attempt to preserve the underlying datatypes more effectively.
4) Assumes no column names are repeated. If they are, then you have to check if a column item has already been added, and then create an ColName2 column in the parsing section.

Categories