Print an array/list to excel in c# - c#

I am able to save a single value into excel but I need help to save a full list/array into an excel sheet.
Code I have so far:
var MovieNames = session.Query<Movie>()
.ToArray();
List<string> MovieList = new List<string>();
foreach (var movie in MovieNames)
{
MovieList.Add(movie.MovieName);
}
//If I want to print a single value or a string,
//I can use the following to print/save to excel
// How can I do this if I want to print that entire
//list thats generated in "MovieList"
return File(new System.Text.UTF8Encoding().GetBytes(MovieList), "text/csv", "demo.csv");

You could use FileHelpers to serialize some strongly typed object into CSV. Just promise me to never roll your own CSV parser.

If you mean you want to create a .csv file with all movie names in one column so you can open it in Excel then simply loop over it:
byte[] content;
using (var ms = new MemoryStream())
{
using (var writer = new StreamWriter(ms))
{
foreach (var movieName in MovieList)
writer.WriteLine(movieName);
}
content = ms.ToArray();
}
return File(content, "text/csv", "demo.csv");
Edit
You can add more columns and get fancier with your output but then you run into the problem that you have check for special characters which need escaping (like , and "). If you want to do more than just a simple output then I suggest you follow #Darins suggestion and use the FileHelpers utilities. If you can't or don't want to use them then this article has an implementation of a csv writer.

Related

Read a docx file in C# using OpenXml

I am new to C# and OpenXml. I need help with reading a .docx file and storing each paragraph in the Array.
I am Using OpenXml to read a word(.docx) file. I was able to read the file and print it. But the problem is I was only able to print the concatenated paragraph. I couldn't find a way to store each paragraph as array of Strings(Like in Python using docx library you automatically store paragraph as a list of string, I was looking something similar to that).
using System;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
OpenWordprocessingDocumentReadonly(#"E:\WordDocTest\Test.docx");
}
public static void OpenWordprocessingDocumentReadonly(string filepath)
{
// Open a WordprocessingDocument based on a filepath.
using (WordprocessingDocument wordDocument =
WordprocessingDocument.Open(filepath, false))
{
// Assign a reference to the existing document body.
Body body = wordDocument.MainDocumentPart.Document.Body;
Console.WriteLine(body.InnerText);
wordDocument.Close();
}
}
}
}
Test.docx Looks Like this
1. Test
This is Test 1.
Test1 part a.
2. noTest
This is Test2.
The Output that I got was : TestThis is Test 1.Test1 part a.noTestThis is Test 2.
What I want to learn is about the way to store each paragraph or line in an Array of String and be able to iterate through that array.
#Nirakar Nepal You could try loop through the paras list and extract the next sibling, e.g. 'foreach (var para in paras) { richTextBox1.Text += para.NextSibling().InnerText + "\n"; } ' This of course assumes you are printing the output to a richtextbox. This will show whatever happens to be after the headingYou can avoid using arrays and instead unleash the wonderful power of Openxml combined with Linq and Lists. If you want to work with paragraphs you could create a list lik this:
var paras = body.OfType<Paragraph>();
You can then expand on this to return specific elements using Where, for example:
var paras = body.OfType<Paragraph>()
.Where(p => p.ParagraphProperties != null &&
p.ParagraphProperties.ParagraphStyleId != null &&
p.ParagraphProperties.ParagraphStyleId.Val.Value.Contains("Heading1")).ToList();
To return the paragraph which follows the heading you could try loop through the paras list and extract the next sibling, e.g.
foreach (var para in paras) {
richTextBox1.Text += para.NextSibling().InnerText + "\n";
}
This of course assumes you are printing the output to a richtextbox. This will show whatever happens to be after the heading. Again your code code could include .where to filter the results

C# - Excel Export a List

Hi i have this code To export a List to An Excel:
private DataTable ListaDatiReportQuietanzamento(List<DatiReportQuietanzamento> datiReportQuietanzamento)
{
DataTable dt = new DataTable("DatiReportQuietanzamento");
dt.Columns.Add("Polizza");
dt.Columns.Add("Posizione");
dt.Columns.Add("Codice Frazionamento");
var result = datiReportQuietanzamento.ToDataTable().AsEnumerable().Select(p =>
new
{
n_polizza = p.Field<long>("n_polizza"),
n_posizione = p.Field<byte>("n_posizione"),
c_frazionamento = p.Field<string>("c_frazionamento")
}).Distinct().ToList();
foreach (var item in result)
{
dt.Rows.Add(item.n_polizza, item.n_posizione, item.c_frazionamento);
}
return dt;
}
This method works with Lists that does not contain many items , but when the list is very large , the method takes too many time.
There is a way to avoid the foreach and add to the rows the items directly? Maybe with Lambda Expression?
Thank you.
While you have not specified how the data is ultimately to be supplied to Excel, generally it is supplied a CSV (Comma Separated Values) file for easy import.
So this being the case you can eliminate your data table conversion entirely and create a list of strings as follows:
private List<string> ListaDatiReportQuietanzamento(List<DatiReportQuietanzamento> datiReportQuietanzamento)
{
var result = new List<string>();
foreach (var item in datiReportQuietanzamento)
{
result.AppendLine($"{item.n_polizza},{item.n_posizione},{item.c_frazionamento}");
}
return result;
}
Now the only simplification I have made is not to worry about encoding because strings should actually be escaped so item.c_frazionamento should actually be escaped.
Instead of doing this all yourself, I suggest you have a look at a NuGet package such as CsvHelper which will help you with creating CSV files and take all the hassle with escaping things out of the equation. It can also directly deal with a list of objects and convert it into a CSV file for you see specifically the first example in https://joshclose.github.io/CsvHelper/writing#writing-all-records

Determine if input file is usable by program

I have a C# program that looks through directories for .txt files and loads each into a DataTable.
static IEnumerable<string> ReadAsLines(string fileName)
{
using (StreamReader reader = new StreamReader(fileName))
while (!reader.EndOfStream)
yield return reader.ReadLine();
}
public DataTable GetTxtData()
{
IEnumerable<string> reader = ReadAsLines(this.File);
DataTable txtData = new DataTable();
string[] headers = reader.First().Split('\t');
foreach (string columnName in headers)
txtData.Columns.Add(columnName);
IEnumerable<string> records = reader.Skip(1);
foreach (string rec in records)
txtData.Rows.Add(rec.Split('\t'));
return txtData;
}
This works great for regular tab-delimited files. However, the catch is that not every .txt file in the folders I need to use contains tab-delimited data. Some .txt files are actually SQL queries, notes, etc. that have been saved as plain text files, and I have no way of determining that beforehand. Trying to use the above code on such files clearly won't lead to the expected result.
So my question is this: How can I tell whether a .txt file actually contains tab-delimited data before I try to read it into a DataTable using the above code?
Just searching the file for any tab character won't work because, for example, a SQL query saved as plain text might have tabs for code formatting.
Any guidance here at all would be much appreciated!
If each line contains the same number of elements, then simply read each line, and verify that you get the correct number of fields in each record. If not error out.
if (headers.Count() != CORRECTNUMBER)
{
// ERROR
}
foreach (string rec in records)
{
string[] recordData = rec.Split('\t');
if (recordData.Count() != headers.Count())
{
// ERROR
}
txtData.Rows.Add(recordData);
}
To do this you need a set of "signature" logic providers which can check a given sample of the file for "signature" content. This is similar to how virus scanners work.
Consider you would create a set of classes where the ISignature was implemented by set of classes;
class TSVFile : ISignature
{
enumFileType ISignature.Evaluate(IEnumerable<byte> inputStream);
}
class SQLFile : ISignature
{
enumFileType ISignature.Evaluate(IEnumerable<byte> inputStream);
}
each one would read an appropriate number of bytes in and return the known file type, if it can be evaluated. Each file parser would need its own logic to determine how many bytes to read and on what basis to make its evaluation.

SearchResultCollection to CSV

Is there any easy way to export the contents of my results (SearchResultCollection) to a CSV file?
or do I have to Iterate each result and Append it to a text file?
Is there any easy way to export the contents of my results
(SearchResultCollection) to a CSV file or do I have to Iterate each
result and Append it to a text file?
No, there is no better option than iterating the SearchResultCollection and writing it to a text-file.
using (StreamWriter w = File.AppendText(path))
{
foreach (SearchResult result in allSearchResults)
{
w.WriteLine(string.Format("Path={0} Properties={1}"
, result.Path
, string.Join(",", result.Properties.PropertyNames));
}
}

How can I utilize StreamWriter to write to a csv file?

So here's what I'm working with. I'm trying to take an XML file, pull the info from the attributes, append them together, and write it to a CSV file. I'm still relatively new to programming, and the other programmer is out of the office today, so I could really use some assistance.
My first question, regards the StringBuilder. Do I need to have an AppendLine at the end of my StringBuilder, so that each string output from the foreach loop is on a new line? And would I need to do that inside the foreach loop?
My second question regards actually writing my string to the CSV file. Would it look something like?
swOutputFile.WriteLine(strAppendedJobData)
And I think this would also go inside the foreach loop, but I'm not too sure.
Thanks for the help, I hope I've worded my question in a somewhat easy to understand manner.
//Create a stream writer to write the data from returned XML job ticket to a new CSV
StreamWriter swOutputFile;
string strComma = ",";
swOutputFile = new StreamWriter(new FileStream("C:\\Dev\\AppendedJobData.csv", FileMode.Create, FileAccess.Write, FileShare.Read));
//Get nodes from returned XML ticket
XmlNodeList xmlJobs = xdResults.SelectNodes("/Updates/Jobs/Job");
//Pull out data from XML attributes
foreach (XmlElement xeJobUpdate in xmlJobs)
{
//Break down the job data
string strProjectID = xeJobUpdate.GetAttribute("SharpOwlProjectID");
string strJobNumber = xeJobUpdate.GetAttribute("JobNumber");
string strClientCode = xeJobUpdate.GetAttribute("SharpOwlClientCode");
string strClient = xeJobUpdate.GetAttribute("Client");
string strVCAOffice = xeJobUpdate.GetAttribute("VCAOffice");
string strLoadStatus = xeJobUpdate.GetAttribute("LoadStatus");
//Build the string to be added to the new CSV file
StringBuilder sbConcatJob = new StringBuilder();
sbConcatJob.Append(strProjectID).Append(strComma).Append(strJobNumber)
.Append(strComma).Append(strClientCode).Append(strComma).Append(strClient).Append(strComma)
.Append(strVCAOffice).Append(strComma).Append(strLoadStatus).Append(strComma);
string strAppendedJobData = sbConcatJob.ToString();
if you want to do it a bit more elegant you could do something like that:
using(StreamWriter swOutputFile = new StreamWriter(new FileStream("C:\\Dev\\AppendedJobData.csv", FileMode.Create, FileAccess.Write, FileShare.Read)))
{
//Get nodes from returned XML ticket
XmlNodeList xmlJobs = xdResults.SelectNodes("/Updates/Jobs/Job");
//Pull out data from XML attributes
foreach (XmlElement xeJobUpdate in xmlJobs)
{
List<String> lineItems = new List<String>();
lineItems.add(xeJobUpdate.GetAttribute("SharpOwlProjectID"));
//add all the other items
swOutputFile.WriteLine(String.Join(',', myLine.ToArray()));
}
//after the loop you close the writer
}
//all the work is done much easier
My first question, regards the
StringBuilder. Do I need to have an
AppendLine at the end of my
StringBuilder, so that each string
output from the foreach loop is on a
new line? And would I need to do that
inside the foreach loop?
My only advice since it appears you have not attempted this would be to try it. It is the only way you will learn.
swOutputFile.WriteLine(strAppendedJobData)
This would write an entire line of text to a file.
You really have two options here:
If you call sbConcatJob.AppendLine() inside the foreach loop you can build the contents of the file in one string builder then call swOutputFile.Write(sbConcatJob.ToString()) outside of the foreach loop to write the file.
If you keep your code as it is now you can add sw.OutputFile.WriteLine(sbConcatJob.ToString()) inside the foreach loop and write the file one line at a time.

Categories