I have this block of code and want to insert headers before it writes. I have tried various ways but it keeps reading and mixing the headers with the data being written to file. I tried adding the heading outside the if block but it still makes no difference, I also tried adding it right after the file is created but same result. I would like to know how to add it without it mixing with the data
using (StreamWriter stream = new StreamWriter("cross_check.xls", true))
{
if (stream == null)
{
MessageBox.Show("File can't be written");
}
else
{
stream.WriteLine();
stream.Write(search.Text);
stream.Write("\t ");
stream.Write(textBox1.Text);
MessageBox.Show("Data Added Successfully");
}
You can include the header when you write data to file. But if you have some existing files which need modification and if the content of your excel file is text contents (which seems to be, based on the question), you can simply use File.ReadAllLines and File.WriteAllLines this way:
var file = #"d:\file.xls";
var lines = System.IO.File.ReadAllLines(file).ToList();
lines.Insert(0, "Some text");
System.IO.File.WriteAllLines(file, lines);
Using File.ReadAllLines you have all lines of your file and you can perform additional processing on file contents too. For example you can split all lines by a delimiter and manipulate each cell or add new columns and so on. Also you can shape the result into a data structure like DataTable and show it in DataGridView to edit them and save them back to the file again.
Related
For the following operation:
Open a text file
Search and replace all searching characters with new characters
I'd like to achieve above in c#, here is my code:
using (StreamReader sr = new StreamReader(#"S:\Personal Folders\A\TESTA.txt"))
{
using (StreamWriter sw = new StreamWriter(#"S:\Personal Folders\A\TESTB.txt"))
{
string line;
while ((line = sr.ReadLine())!= null)
{
if (!line.Contains("before"))
{
sw.WriteLine(line);
}
else if (line.Contains("before"))
{
sw.WriteLine(line.Replace("before", "after"));
}
}
}
}
Basically, the above code will generate a new file with the desired replace operation, but as you can see, the way I am doing is read each line of the original file and write to a new file. This could achieve my goal, but it may have system IO issue because it is reading and writing for each line. Also, I cannot read all the lines to an array first, and then write, because the file is large and if I try to write to an string[], replace all, then write the array to the file, will bring about the memory timeout issue.
Is there any way that I can just locate to the specific lines, and just replace those lines and keep all the rest? Or What is the best way to solve the above problem? Thanks
I don't know what IO issue you are worried about, but your code should work ok. You can code more concisely as follows:
using (StreamReader sr = new StreamReader(#"S:\Personal Folders\A\TESTA.txt"))
{
using (StreamWriter sw = new StreamWriter(#"S:\Personal Folders\A\TESTB.txt"))
{
while ((string line = sr.ReadLine())!= null)
{
sw.WriteLine(line.Replace("before", "after"));
}
}
}
This will run a bit faster because it searches for "before" only once per line. By default the StreamWriter buffers your writes and does not flush to the disk each time you call WriteLine, and file IO is asynchronous in the operating system, so don't worry so much about IO.
In general, what you are doing is correct, possibly followed by some renames to replace the original file. If you do want to replace the original file, you should rename the original file to a temporary name, rename the new file to the original name, and then either leave or delete the original file. You must handle conflicts with your temporary name and errors in all renames.
Consider you are replacing a six character string with a five character string - if you write back to the original file, what will you do with the extra characters? Files are stored on disk as raw bytes of data, there is no "text" file on disk. What if you replace a string with a longer one - you then potentially have to move the entire rest of the file to make room to write the longer line.
You can imagine the file on disk as letters written on graph paper in the boxes. The end of each line is noted by a special character (or characters - in Windows, that is CRLF), the characters fill all the boxes horizontally. If you tried to replace words on the graph paper you would have to erase and re-write lots of letters. Writing on a new sheet will be easiest.
Well, your approach is basically fine... but I wouldn't check if the line contains the word before... the trade-off is not good enough:
using (StreamReader sr = new StreamReader(#"S:\Personal Folders\A\TESTA.txt"))
{
using (StreamWriter sw = new StreamWriter(#"S:\Personal Folders\A\TESTB.txt"))
{
String line;
while ((line = sr.ReadLine()) != null)
sw.WriteLine(line.Replace("before", "after"));
}
}
Try following :
else if (line.Contains("before"))
{
sw.WriteLine(line.Replace("before", "after"));
sw.Write(sr.ReadToEnd());
break;
}
I'm generating the head of different CSV files so my users can see the format
var output = new MemoryStream()
var writer = new StreamWriter(output, Encoding.UTF8);
//this function gets the row depending of the enumerator name in this format a;b;c;d
var header = ModelosCsv.GetCsvByEnum("HeadRowFileLoad");
writer.WriteLine(header);
writer.Flush();
output.Position = 0;
return File(output, "application/csv", "format.csv");
The code is creating the CSV correctly but if they open the CSV with excel and save it, excel will overwrite all the ";" for triple spaces.
If I edit the result with notepad++ and put back the ";" excel won't do it again.
I have opened both archives with excel and clicked "save as", the first one (freshly generated by c#) is set as default as "text archive" the second one (edited by notepad++) is set as CSV.
Am I missing something code?
How could I do to stop excel messing up my archives?
I found the solution in this answered question
Export to CSV using MVC, C# and jQuery
var header = ModelosCsv.GetCsvByEnum("HeadRowFileLoad");
return File(new System.Text.UTF8Encoding().GetBytes(header), "application/csv", "format.csv");
This way Excel identifies the archive as CSV and editing wont break the format.
I have this bit of code below which saves perfectly fine to a text file, however there is no formatting that is transferred, for example, The below words would save as THISISATESTLAYOUT. I would like the desired output displayed below:
THIS
IS
A
TEST
LAYOUT
I know there's something obvious im missing here so thanks for any help
if (entity.Switch == true)
{
string path = #"filepath....\\Test.txt";
if (!File.Exists(path))
{
// Create a file to write to.
using (StreamWriter sw = File.CreateText(path))
{
sw.Write(entity.comments);
}
}
}
this string is saved in one entity called comments and displays fine within the C# application.
sw.Write and sw.WriteLine both give the same single line output with no spaces
and also entity.comments references a column in an SQL Server Table, and is a VARCHAR(MAX)
you may be using '\n' for newlines. If so use
sw.Write(entity.comments.Replace("\n", "\r\n"));
Change sw.Write to sw.WriteLine
I think my question is simple. I've searched but not found a solution for the method that I'm actually using.
I save the content of a listbox into a text file with success, but I'm having problem on load.
For create the file, I use:
using(StreamWriter file = File.CreateText(path))
To write the content from the listbox to file, I use:
foreach (string content in listDOF.Items)
{
file.WriteLine(content);
}
This works very well.
Now, I just need load the saved content with succes.
I've tried:
if (File.Exists(filesrc))
{
File.OpenRead(filesrc);
string[] line = System.IO.File.ReadAllLines(filesrc);
listDOF.Items.Add(line);
}
But this does not work and give me an exception.
How to do this correctily? Thanks all in advance! :)
You are adding an array of strings. The method to use is AddRange
string[] lines = System.IO.File.ReadAllLines(filesrc);
listDOF.Items.AddRange(lines);
The File.OpenRead is not needed. You could remove that line
What I'm trying to accomplish
My app generates some tabular data
I want the user to be able to launch Excel and click "paste" to place the data as cells in Excel
Windows accepts a format called "CommaSeparatedValue" that is used with it's APIs so this seems possible
Putting raw text on the clipboard works, but trying to use this format does not
NOTE: I can correctly retrieve CSV data from the clipboard, my problem is about pasting CSV data to the clipboard.
What I have tried that isn't working
Clipboard.SetText()
System.Windows.Forms.Clipboard.SetText(
"1,2,3,4\n5,6,7,8",
System.Windows.Forms.TextDataFormat.CommaSeparatedValue
);
Clipboard.SetData()
System.Windows.Forms.Clipboard.SetData(
System.Windows.Forms.DataFormats.CommaSeparatedValue,
"1,2,3,4\n5,6,7,8",
);
In both cases something is placed on the clipboard, but when pasted into Excel it shows up as one cell of garbarge text: "–§žý;pC¦yVk²ˆû"
Update 1: Workaround using SetText()
As BFree's answer shows SetText with TextDataFormat serves as a workaround
System.Windows.Forms.Clipboard.SetText(
"1\t2\t3\t4\n5\t6\t7\t8",
System.Windows.Forms.TextDataFormat.Text
);
I have tried this and confirm that now pasting into Excel and Word works correctly. In each case it pastes as a table with cells instead of plaintext.
Still curious why CommaSeparatedValue is not working.
The .NET Framework places DataFormats.CommaSeparatedValue on the clipboard as Unicode text. But as mentioned at http://www.syncfusion.com/faq/windowsforms/faq_c98c.aspx#q899q, Excel expects CSV data to be a UTF-8 memory stream (it is difficult to say whether .NET or Excel is at fault for the incompatibility).
The solution I've come up with in my own application is to place two versions of the tabular data on the clipboard simultaneously as tab-delimited text and as a CSV memory stream. This allows the destination application to acquire the data in its preferred format. Notepad and Excel prefer the tab-delimited text, but you can force Excel to grab the CSV data via the Paste Special... command for testing purposes.
Here is some example code (note that WinForms-equivalents from the WPF namespaces are used here):
// Generate both tab-delimited and CSV strings.
string tabbedText = //...
string csvText = //...
// Create the container object that will hold both versions of the data.
var dataObject = new System.Windows.DataObject();
// Add tab-delimited text to the container object as is.
dataObject.SetText(tabbedText);
// Convert the CSV text to a UTF-8 byte stream before adding it to the container object.
var bytes = System.Text.Encoding.UTF8.GetBytes(csvText);
var stream = new System.IO.MemoryStream(bytes);
dataObject.SetData(System.Windows.DataFormats.CommaSeparatedValue, stream);
// Copy the container object to the clipboard.
System.Windows.Clipboard.SetDataObject(dataObject, true);
Use tabs instead of commas. ie:
Clipboard.SetText("1\t2\t3\t4\t3\t2\t3\t4", TextDataFormat.Text);
Just tested this myself, and it worked for me.
I have had success pasting into Excel using \t (see BFree's answer) as column separators and \n as row separators.
I got the most success defeating formatting issues by using a CSV library (KBCsv) to write the data into a CSV file in the temp folder then open it in Excel with Process.Start(). Once it is in Excel the formatting bit is easy(er), copy-paste from there.
string filePath = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
using (var streamWriter = new StreamWriter(filePath))
using (CsvWriter csvWriter = new CsvWriter(streamWriter))
{
// optional header
csvWriter.WriteRecord(new List<string>(){"Heading1", "Heading2", "YouGetTheIdea" });
csvWriter.ValueSeparator = ',';
foreach (var thing in YourListOfThings ?? new List<OfThings>())
{
if (thing != null)
{
List<string> csvLine = new List<string>
{
thing.Property1, thing.Property2, thing.YouGetTheIdea
};
csvWriter.WriteRecord(csvLine);
}
}
}
Process.Start(filePath);
BYO Error handing & logging.