Create a .csv file in C# - c#

Alright I want to create a .csv file in C#. I have been looking around and noticed a lot of people are using the system.IO.memorystream and system.io.streamwriter.
The problem is this: I have a web application. I want to give the user the ability to export to excel. Problem is, Excel cannot be installed on the server (don't ask). I want to be able to write an .csv sheet export for a report. Now, the reports headers and data will be different for all of the reports (looping through will solve this). Anybody have an example or better resources for me to go through?

This the approach i normally take. Probably not the most efficient though.
/// <summary>
/// Generates the contents of the log file.
/// </summary>
/// <returns>The contents of the log file.</returns>
internal string GenerateLogFile()
{
StringBuilder csvExport = new StringBuilder();
csvExport.AppendLine(Resources.CSVHeader);
foreach (DataRow row in this.logEntries.Rows)
{
csvExport.AppendLine(
string.Format(
"\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\", \"{9}\"",
row[ColumnNames.LogTime], row[ColumnNames.Field1], row[ColumnNames.Field2], row[ColumnNames.Field3], row[ColumnNames.Field4], row[ColumnNames.Field5], row[ColumnNames.Field6], row[ColumnNames.Field7], row[ColumnNames.Field8], row[ColumnNames.Field9]));
}
return csvExport.ToString();
}
/// <summary>
/// Adds the CSV file to the response.
/// </summary>
/// <param name="csvExportContents">The contents of the CSV file.</param>
internal void DisplayLogFile(string csvExportContents)
{
byte[] data = new ASCIIEncoding().GetBytes(csvExportContents);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "APPLICATION/OCTET-STREAM";
HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment; filename=Export.csv");
HttpContext.Current.Response.OutputStream.Write(data, 0, data.Length);
HttpContext.Current.Response.End();
}

private void WriteItem<T>(StreamWriter sr, T item)
{
string itemString = item.ToString();
if(itemString.IndexOfAny(new char[] { '"', ',', '\n', '\r' }) != -1)//skip test and always escape for different speed/filesize optimisation
{
sr.Write('"');
sr.Write(itemString.Replace("\"", "\"\""));
sr.Write('"');
}
else
sr.Write(itemString);
}
private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line)
{
bool first = true;
foreach(T item in line)
{
if(!first)
sr.Write(',');
first = false;
WriteItem(sr, item);
}
}
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines)
{
bool first = true;
foreach(IEnumerable<T> line in allLines)
{
if(!first)
sr.Write('\n');
first = false;
WriteLine(sr, line);
}
}
private void WriteCSV<T>(HttpResponse response, IEnumerable<IEnumerable<T>> allLines)
{
response.ContentType = "text/csv";
WriteCSV(response.Output, allLines);
}
It can be worth also sending a content-disposition header with a recommended filename.
Edit: Of late, with cases where one needs to interspace an action between items in an enumeration (like the comma and newline above), I've preferred that rather keeping a boolean that keeps being checked, I handle the enumerator directly, and then handle the first element separate from the rest. I started doing this as a micro-opt in a efficiency-push but have grown to just find it a better expression of a code-path that differs for the first item. As such, I'd now write the above as:
private void WriteLine<T>(StreamWriter sr, IEnumerable<T> line)
{
using(var en = line.GetEnumerator())
if(en.MoveNext())
{
WriteItem(sr, en.Current);
while(en.MoveNext())
{
sr.Write(',');
WriteItem(sr, en.Current);
}
}
private void WriteCSV<T>(StreamWriter sr, IEnumerable<IEnumerable<T>> allLines)
{
using(var en = allLines.GetEnumerator())
if(en.MoveNext())
{
WriteLine(sr, en.Current);
while(en.MoveNext())
{
sr.Write('\n');
WriteLine(sr, en.Current);
}
}
}

You should be able to use the examples using System.IO.MemoryStream and System.IO.StreamWriter just fine.
Instead of writing the MemoryStream out to a file, you would return it as the ResponseStream in ASP.NET (making sure that you set the appropriate header values so the browser knows that it's downloading a file).

Excel is only required if you are using Office Interop. Using StringWriter, you are simply going to create a file and add some response information. Excel is only required when opening the file.

There is really no magic in creating a CSV file. The only problem with CSV files is that there is not really a standard, and most importers will just implement one particular behavior for the import process. If you are lucky, you will get something that can guess relatively well.
Generating the CSV file is just a matter of printing the lines. As for the actual details, familiarize yourself with:
http://en.wikipedia.org/wiki/Comma-separated_values
That being said, if what you want is to export to Excel, you could use Microsoft's OOXML SDK:
http://msdn.microsoft.com/en-us/library/bb448854.aspx
The OOXML SDK is a C# library that you can use to generate Excel files on the server. The Brian Jones blog is a great resource on how to use this library:
http://blogs.msdn.com/b/brian_jones/

If you don't mind using a 3rd party library and the LGPL license is okay in your project, then FileHelpers is a great tool for this.

This is the function used to create csv file:
private async Task<string> WriteCSV<ViewModel>(IEnumerable<ViewModel> viewModels, string path)
{
Type itemType = typeof(ViewModel);
var props = itemType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.OrderBy(p => p.Name);
var blobName = string.Empty;
using (var ms = new MemoryStream())
{
using (var writer = new System.IO.StreamWriter(ms))
{
writer.WriteLine(string.Join(", ", props.Select(p => p.Name)));
foreach (var item in viewModels)
{
writer.WriteLine(string.Join(", ", props.Select(p => p.GetValue(item, null))));
}
}
}
}
Otherwise you can refer below link:
https://travelcodingnlotsmore.wordpress.com/2013/06/06/creating-csv-file-from-data-in-list-object-in-c/

Related

How can I debug my add-in when WordEditor's Content property is crashing Outlook?

I have folder full of *.msg files saved from Outlook and I'm trying to convert them to Word.
There is a loop that loads each *.msg as MailItem and saves them.
public static ConversionResult ConvertEmailsToWord(this Outlook.Application app, string source, string target)
{
var word = new Word.Application();
var emailCounter = 0;
var otherCounter = 0;
var directoryTree = new PhysicalDirectoryTree();
foreach (var node in directoryTree.Walk(source))
{
foreach (var fileName in node.FileNames)
{
var currentFile = Path.Combine(node.DirectoryName, fileName);
var branch = Regex.Replace(node.DirectoryName, $"^{Regex.Escape(source)}", string.Empty).Trim('\\');
Debug.Print($"Processing file: {currentFile}");
// This is an email. Convert it to Word.
if (Regex.IsMatch(fileName, #"\.msg$"))
{
if (app.Session.OpenSharedItem(currentFile) is MailItem item)
{
if (item.SaveAs(word, Path.Combine(target, branch), fileName))
{
emailCounter++;
}
item.Close(SaveMode: OlInspectorClose.olDiscard);
}
}
// This is some other file. Copy it as is.
else
{
Directory.CreateDirectory(Path.Combine(target, branch));
File.Copy(currentFile, Path.Combine(target, branch, fileName), true);
otherCounter++;
}
}
}
word.Quit(SaveChanges: false);
return new ConversionResult
{
EmailCount = emailCounter,
OtherCount = otherCounter
};
}
The save method looks likes this:
public static bool SaveAs(this MailItem mail, Word.Application word, string path, string name)
{
Directory.CreateDirectory(path);
name = Path.Combine(path, $"{Path.GetFileNameWithoutExtension(name)}.docx");
if (File.Exists(name))
{
return false;
}
var copy = mail.GetInspector.WordEditor as Word.Document;
copy.Content.Copy();
var doc = word.Documents.Add();
doc.Content.Paste();
doc.SaveAs2(FileName: name);
doc.Close();
return true;
}
It works for most *.msg files but there are some that crash Outlook when I call copy.Content on a Word.Document.
I know you cannot tell me what is wrong with it (or maybe you do?) so I'd like to findit out by myself but the problem is that I am not able to catch the exception. Since a simple try\catch didn't work I tried it with AppDomain.CurrentDomain.UnhandledException this this didn't catch it either.
Are there any other ways to debug it?
The mail that doesn't let me get its content inside a loop doesn't cause any troubles when I open it in a new Outlook window and save it with the same method.
It makes sense to add some delays between Word calls. IO operations takes some time to finish. Also there is no need to create another document in Word for copying the content:
var copy = mail.GetInspector.WordEditor as Word.Document;
copy.Content.Copy();
var doc = word.Documents.Add();
doc.Content.Paste();
doc.SaveAs2(FileName: name);
doc.Close();
Instead, do the required modifications on the original document instance and then save it to the disk. The original mail item will remain unchanged until you call the Save method from the Outlook object model. You may call the Close method passing the olDiscard which discards any changes to the document.
Also consider using the Open XML SDK if you deal with open XML documents only, see Welcome to the Open XML SDK 2.5 for Office for more information.
Do you actually need to use Inspector.WordEditor? You can save the message in a format supported by Word (such as MHTML) using OOM alone by calling MailItem.Save(..., olMHTML) and open the file in Word programmatically to save it in the DOCX format.

broken diacritic when writing to file [duplicate]

There are a lot of different ways to read and write files (text files, not binary) in C#.
I just need something that is easy and uses the least amount of code, because I am going to be working with files a lot in my project. I only need something for string since all I need is to read and write strings.
Use File.ReadAllText and File.WriteAllText.
MSDN example excerpt:
// Create a file to write to.
string createText = "Hello and Welcome" + Environment.NewLine;
File.WriteAllText(path, createText);
...
// Open the file to read from.
string readText = File.ReadAllText(path);
In addition to File.ReadAllText, File.ReadAllLines, and File.WriteAllText (and similar helpers from File class) shown in another answer you can use StreamWriter/StreamReader classes.
Writing a text file:
using(StreamWriter writetext = new StreamWriter("write.txt"))
{
writetext.WriteLine("writing in text file");
}
Reading a text file:
using(StreamReader readtext = new StreamReader("readme.txt"))
{
string readText = readtext.ReadLine();
}
Notes:
You can use readtext.Dispose() instead of using, but it will not close file/reader/writer in case of exceptions
Be aware that relative path is relative to current working directory. You may want to use/construct absolute path.
Missing using/Close is very common reason of "why data is not written to file".
FileStream fs = new FileStream(txtSourcePath.Text,FileMode.Open, FileAccess.Read);
using(StreamReader sr = new StreamReader(fs))
{
using (StreamWriter sw = new StreamWriter(Destination))
{
sw.Writeline("Your text");
}
}
The easiest way to read from a file and write to a file:
//Read from a file
string something = File.ReadAllText("C:\\Rfile.txt");
//Write to a file
using (StreamWriter writer = new StreamWriter("Wfile.txt"))
{
writer.WriteLine(something);
}
using (var file = File.Create("pricequote.txt"))
{
...........
}
using (var file = File.OpenRead("pricequote.txt"))
{
..........
}
Simple, easy and also disposes/cleans up the object once you are done with it.
#AlexeiLevenkov pointed me at another "easiest way" namely the extension method. It takes just a little coding, then provides the absolute easiest way to read/write, plus it offers the flexibility to create variations according to your personal needs. Here is a complete example:
This defines the extension method on the string type. Note that the only thing that really matters is the function argument with extra keyword this, that makes it refer to the object that the method is attached to. The class name does not matter; the class and method must be declared static.
using System.IO;//File, Directory, Path
namespace Lib
{
/// <summary>
/// Handy string methods
/// </summary>
public static class Strings
{
/// <summary>
/// Extension method to write the string Str to a file
/// </summary>
/// <param name="Str"></param>
/// <param name="Filename"></param>
public static void WriteToFile(this string Str, string Filename)
{
File.WriteAllText(Filename, Str);
return;
}
// of course you could add other useful string methods...
}//end class
}//end ns
This is how to use the string extension method, note that it refers automagically to the class Strings:
using Lib;//(extension) method(s) for string
namespace ConsoleApp_Sandbox
{
class Program
{
static void Main(string[] args)
{
"Hello World!".WriteToFile(#"c:\temp\helloworld.txt");
return;
}
}//end class
}//end ns
I would never have found this myself, but it works great, so I wanted to share this. Have fun!
These are the best and most commonly used methods for writing to and reading from files:
using System.IO;
File.AppendAllText(sFilePathAndName, sTextToWrite);//add text to existing file
File.WriteAllText(sFilePathAndName, sTextToWrite);//will overwrite the text in the existing file. If the file doesn't exist, it will create it.
File.ReadAllText(sFilePathAndName);
The old way, which I was taught in college was to use stream reader/stream writer, but the File I/O methods are less clunky and require fewer lines of code. You can type in "File." in your IDE (make sure you include the System.IO import statement) and see all the methods available. Below are example methods for reading/writing strings to/from text files (.txt.) using a Windows Forms App.
Append text to an existing file:
private void AppendTextToExistingFile_Click(object sender, EventArgs e)
{
string sTextToAppend = txtMainUserInput.Text;
//first, check to make sure that the user entered something in the text box.
if (sTextToAppend == "" || sTextToAppend == null)
{MessageBox.Show("You did not enter any text. Please try again");}
else
{
string sFilePathAndName = getFileNameFromUser();// opens the file dailog; user selects a file (.txt filter) and the method returns a path\filename.txt as string.
if (sFilePathAndName == "" || sFilePathAndName == null)
{
//MessageBox.Show("You cancalled"); //DO NOTHING
}
else
{
sTextToAppend = ("\r\n" + sTextToAppend);//create a new line for the new text
File.AppendAllText(sFilePathAndName, sTextToAppend);
string sFileNameOnly = sFilePathAndName.Substring(sFilePathAndName.LastIndexOf('\\') + 1);
MessageBox.Show("Your new text has been appended to " + sFileNameOnly);
}//end nested if/else
}//end if/else
}//end method AppendTextToExistingFile_Click
Get file name from the user via file explorer/open file dialog (you will need this to select existing files).
private string getFileNameFromUser()//returns file path\name
{
string sFileNameAndPath = "";
OpenFileDialog fd = new OpenFileDialog();
fd.Title = "Select file";
fd.Filter = "TXT files|*.txt";
fd.InitialDirectory = Environment.CurrentDirectory;
if (fd.ShowDialog() == DialogResult.OK)
{
sFileNameAndPath = (fd.FileName.ToString());
}
return sFileNameAndPath;
}//end method getFileNameFromUser
Get text from an existing file:
private void btnGetTextFromExistingFile_Click(object sender, EventArgs e)
{
string sFileNameAndPath = getFileNameFromUser();
txtMainUserInput.Text = File.ReadAllText(sFileNameAndPath); //display the text
}
Or, if you are really about lines:
System.IO.File also contains a static method WriteAllLines, so you could do:
IList<string> myLines = new List<string>()
{
"line1",
"line2",
"line3",
};
File.WriteAllLines("./foo", myLines);
It's good when reading to use the OpenFileDialog control to browse to any file you want to read. Find the code below:
Don't forget to add the following using statement to read files: using System.IO;
private void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
textBox1.Text = File.ReadAllText(openFileDialog1.FileName);
}
}
To write files you can use the method File.WriteAllText.
class Program
{
public static void Main()
{
//To write in a txt file
File.WriteAllText("C:\\Users\\HP\\Desktop\\c#file.txt", "Hello and Welcome");
//To Read from a txt file & print on console
string copyTxt = File.ReadAllText("C:\\Users\\HP\\Desktop\\c#file.txt");
Console.Out.WriteLine("{0}",copyTxt);
}
}
private void Form1_Load(object sender, EventArgs e)
{
//Write a file
string text = "The text inside the file.";
System.IO.File.WriteAllText("file_name.txt", text);
//Read a file
string read = System.IO.File.ReadAllText("file_name.txt");
MessageBox.Show(read); //Display text in the file
}
Reading from file
string filePath = #"YOUR PATH";
List<string> lines = File.ReadAllLines(filePath).ToList();
Writing to file
List<string> lines = new List<string>();
string a = "Something to be written"
lines.Add(a);
File.WriteAllLines(filePath, lines);
Simply:
String inputText = "Hello World!";
File.WriteAllText("yourfile.ext",inputText); //writing
var outputText = File.ReadAllText("yourfile.ext"); //reading
You're looking for the File, StreamWriter, and StreamReader classes.

async reading and writing lines of text

I've found plenty of examples of how to read/write text to a file asynchronously, but I'm having a hard time finding how to do it with a List.
For the writing I've got this, which seems to work:
public async Task<List<string>> GetTextFromFile(string file)
{
using (var reader = File.OpenText(file))
{
var fileText = await reader.ReadToEndAsync();
return fileText.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList();
}
}
The writing is a bit trickier though ...
public async Task WriteTextToFile(string file, List<string> lines, bool append)
{
if (!append && File.Exists(file)) File.Delete(file);
using (var writer = File.OpenWrite(file))
{
StringBuilder builder = new StringBuilder();
foreach (string value in lines)
{
builder.Append(value);
builder.Append(Environment.NewLine);
}
Byte[] info = new UTF8Encoding(true).GetBytes(builder.ToString());
await writer.WriteAsync(info, 0, info.Length);
}
}
My problem with this is that for a moment it appears my data is triple in memory.
The original List of my lines, then the StringBuilder makes it a single string with the newlines, then in info I have the byte representation of the string.
That seems excessive that I have to have three copies of essentially the same data in memory.
I am concerned with this because at times I'll be reading and writing large text files.
Following up on that, let me be clear - I know that for extremely large text files I can do this all line by line. What I am looking for are two methods of reading/writing data. The first is to read in the whole thing and process it, and the second is to do it line by line. Right now I am working on the first approach for my small and moderate sized text files. But I am still concerned with the data replication issue.
The following might suit your needs as it does not store the data again as well as writing it line by line:
public async Task WriteTextToFile(string file, List<string> lines, bool append)
{
if (!append && File.Exists(file))
File.Delete(file);
using (var writer = File.OpenWrite(file))
{
using (var streamWriter = new StreamWriter(writer))
foreach (var line in lines)
await streamWriter.WriteLineAsync(line);
}
}

How to remove export to excel warning when exporting datatable

I have the following code, the datatable already has the data and I want to export it to excel.
However I get the following warning, I tried xlsx and it doesnt work.
I also tried csv, and the data does not open into columns as I need.
public static void ExportDatatabletoExcel(DataTable dt, List<string> columnNames)
{
try
{
const string attachment = "attachment; filename=elreport.xls";
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
string tab = "";
foreach (DataColumn dc in dt.Columns)
{
if (!columnNames.Contains(dc.ColumnName)) continue;
HttpContext.Current.Response.Write(tab + dc.ColumnName);
tab = "\t";
}
HttpContext.Current.Response.Write("\n");
int i;
foreach (DataRow dr in dt.Rows)
{
tab = "";
for (i = 0; i < dt.Columns.Count; i++)
{
if(!columnNames.Contains(dt.Columns[i].ColumnName)) continue;
HttpContext.Current.Response.Write(tab + dr[i].ToString());
tab = "\t";
}
HttpContext.Current.Response.Write("\n");
}
HttpContext.Current.Response.End();
}
catch (Exception ex)
{
string errorMessage = String.Format("ExportToExcelError: {0}", ex.Message);
LoggingService.LogError(LoggingCategory.General, ex, errorMessage);
throw;
}
}
Error is:
There are two sure ways to remove the warning.
Build a valid .xlsx file using the OpenXML API or EPPlus API (EPPlus is easier and actually supports OleDB imports)
Build the file as .csv with .csv extension, but leave the content-type as Excel so that it opens with Excel. However, the way you are building the file you may have issues with Excel reading the content correctly, which needs to be addressed:
Excel can only read CSV if it is formatted in certain ways. Also the encoding has to be windows 1252 assuming you are using Excel for windows, or it won't handle foreign chars. Also leading zeros from zip codes etc. need to be dealt with specially for Excel.
public static class CSVExportUtility
{
/// <summary>
/// Open a datatable in Excel
/// </summary>
/// <param name="dt"></param>
/// <param name="fileName"></param>
public static void OpenAsCSV(DataTable dt, string fileName)
{
CSVExportUtility.OpenAsCSV(DataTableToCSV(dt), fileName); // now open the file
} // OpenAsCSV
/// <summary>
/// open the content in the browser as a CSV
/// </summary>
/// <param name="sbCSVFileData"></param>
/// <param name="filename"></param>
public static void OpenAsCSV(StringBuilder sbCSVFileData, string fileName)
{
if (HttpContext.Current == null || HttpContext.Current.Response == null)
return;
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader(
"content-disposition", string.Format("attachment; filename={0}", fileName));
HttpContext.Current.Response.ContentType = "application/ms-excel";
// This is a little tricky. Would like to use utf-8 or unicode... but Excel on Windows uses 1252 by default so we need to keep the same so most users can read the file.
// At some point, we may need to actually convert our text from whatever .NET uses to 1252, but at the moment they seem similar enough that it is okay
HttpContext.Current.Response.ContentEncoding = Encoding.GetEncoding(1252);
// render the htmlwriter into the response
HttpContext.Current.Response.Write(sbCSVFileData.ToString());
HttpContext.Current.Response.End();
}
static StringBuilder DataTableToCSV(DataTable dt)
{
StringBuilder sb = new StringBuilder();
foreach (DataColumn dc in dt.Columns)
{
if (dc == dt.Columns[dt.Columns.Count - 1])
CSVExportUtility.AddFieldForCSV(dc.ColumnName, sb, false, true);
else
CSVExportUtility.AddFieldForCSV(dc.ColumnName, sb, true, false);
}
foreach (DataRow dr in dt.Rows)
{
foreach (DataColumn dc in dt.Columns)
{
if (dc == dt.Columns[dt.Columns.Count - 1])
CSVExportUtility.AddFieldForCSV(FormatDataValue(dr[dc.ColumnName]), sb, false, true);
else
CSVExportUtility.AddFieldForCSV(FormatDataValue(dr[dc.ColumnName]), sb, true, false);
}
}
return sb;
}
static string FormatDataValue(object dv)
{
if (dv == null)
return null;
if (dv is DateTime)
return ((DateTime)dv).ToShortDateString();
else
return dv.ToString();
}
/// <summary>
/// export text to a csv
/// </summary>
/// <param name="text"></param>
/// <param name="sbCSV"></param>
/// <param name="appendTrailingComma"></param>
/// <param name="endOfRow"></param>
public static void AddFieldForCSV(string text, StringBuilder sbCSV, bool appendTrailingComma, bool endOfRow)
{
// shouldn't start or end with whitespace, escape quotes
if (text != null)
text = text.Trim().Replace("\"", "\"\"");
// quote field
int testInt;
if (text != null && text.Trim().Length > 1 && text.Trim()[0] == '0' && int.TryParse(text.Trim(), out testInt))
{ // if text is numeric and starts with '0' tell excel to treat as string and not strip the zero. This ONLY works if it's numeric! Otherwise it fails, example ="a,b" will use 2 cells
text = "=\"" + text.Trim() + "\"";
}
else
{
text = "\"" + text + "\"";
}
sbCSV.Append(text);
if (appendTrailingComma)
sbCSV.Append(",");
if (endOfRow)
sbCSV.AppendLine();
}
}
If you are looking to export a GridView instead of a DataTable, that explanation is at:
http://atakala.com/Browser/Item.aspx?user_id=amos&dict_id=2325
; much of the code is similar (CSVExportUtility methods)
This answer from How to suppress the file corrupt warning at Excel download? addresses some of the problem. I recommend checking out some of the other answers as well.
The alert is a new security feature in Excel 2007 called Extension
Hardening, which ensures that the file content being opened matches
the extension type specified in the shell command that is attempting
to open the file.
...
This issue is still being investigated, but a fix is not likely until
Office 14 given the nature of the complexity of the code, and the fact
that Excel does not want to lower the security measure to workaround
IE open behaviors without a full understanding of the consequences for
other browser users.
Also, this comment might help.
I think that only applies if you're using CSV and save as XLS.
However, if you construct a real excel file, then it should be fine.
CF9 cfspreadsheet will be your friend. :) – Henry Jun 25 '09 at 23:53
Other sources to check:
How to Suppress Extension Warning in Excel
How do you generate an Excel 2007 file in ASP.NET without getting a warning message?
How to avoid warning on opening a programmatically generated Excel file

How to export all the source code from Visual Studio into a text file?

I have a relatively large Visual Studio solution.
I need to export all the source code into a text file. I would also want to include a file name somewhere. How can I do so?
For example if I have a type
namespace MyProject.Core
{
/// <summary>
/// Enumerates possible record status
/// </summary>
public enum RecordType
{
NonWearTime = 0,
WearTime = 1,
NotClassified = 2
}
}
I want this to go to the output.txt file (or any other text format) and appear like so
//***********************************
//Filename: RecordType.cs
//***********************************
namespace MyProject.Core
{
/// <summary>
/// Enumerates possible record status
/// </summary>
public enum RecordType
{
NonWearTime = 0,
WearTime = 1,
NotClassified = 2
}
}
All the other types shall just be appended to the end of the file. I tried Resharper, but its header file options can only contain static text (I tried Filename: $FILENAME$) and the template option only applies to the newly created classes.
Folks, this is a study project, where I have to provide the source code along with a thesis.
This should do the trick
string rootPath = #"path you your root folder";
var header = "***********************************" + Environment.NewLine;
var files = Directory.GetFiles(rootPath, "*.cs", SearchOption.AllDirectories);
var result = files.Select(path => new { Name = Path.GetFileName(path), Contents = File.ReadAllText(path)})
.Select(info =>
header
+ "Filename: " + info.Name + Environment.NewLine
+ header
+ info.Contents);
var singleStr = string.Join(Environment.NewLine, result);
Console.WriteLine ( singleStr );
File.WriteAllText(#"C:\output.txt", singleStr, Encoding.UTF8);
Remarks: if you experience performance or memory inefficiencies, try to use StringBuilder instead and set it's Capacity at the start to the sum of all files contents. This will eliminate lots of redundant strings, created in last Select method.
I would go for a homemade solution.
This helps you get into a String the content of each file.
using System.IO;
...
foreach (string file in Directory.EnumerateFiles(folderPath, "*.cs"))
{
string contents = File.ReadAllText(file);
}
You have the filename, so you can append it at the beginning.
All you still need to do is to parse through all directories.
public void DirSearch(string root)
{
foreach (string file in Directory.EnumerateFiles(root, "*.cs"))
{
string contents = File.ReadAllText(file);
// Write to your outputfile once you've happened what you want in your header.
}
foreach (string d in Directory.GetDirectories(root))
{
DirSearch(d);
}
}
As a none code soloution how about trying a windows command line to merge all files into one.
e.g. copy /b *.cs newfile.txt
https://superuser.com/questions/111825/any-command-line-or-batch-cmd-to-concatenate-multiple-files
Admittedly its quick and dirty, but it might produce what you require with some tailoring
I would write a simple console app to do that. It would search for all files with a *.cs extension, make the necessary modification and then save the file to the desired location. You can loop through directories iteratively using Directory.EnumerateDirectories().

Categories

Resources