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
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 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.
EDIT:
the problem is now solved, it was that there is xml code which is named 'name' which i was accidentally changing. the solution was to have a obscure name in the docx file
I am creating a program that modify a word document using open xml but every time the program runs the file gets corrupt and i don't know why or if there is any way around it?
i have had a look and one thing i saw was too make sure i had closed the connection but i tried that but i'm not sure if the connection is still opened
edit:
the output file says it corrupt but when the recovery in ms word run the files is as it should be
from the images/code
the the original file is copied to temp.docx and has "name" in the file
i require the program to replace "name" with another word.
the program is semi working as it changes the value of the document however it is corrupting the document.
link to photos: https://drive.google.com/open?id=0B130JvN0ZPPRODJpZWZENTNUX0E
CODE
private void gen_btn_Click(object sender, EventArgs e)
{
if (System.IO.File.Exists(#"C:\invoices\temp.docx"))
{
// Use a try block to catch IOExceptions, to
// handle the case of the file already being
// opened by another process.
try
{
System.IO.File.Delete(#"C:\invoices\temp.docx");
}
catch (System.IO.IOException exception)
{
Console.WriteLine(exception.Message);
return;
}
}
File.Copy(#"C:\invoices\template.docx", #"C:\invoices\temp.docx");
SearchAndReplace("name", "asdsadsadasdasdas");
}
public static void SearchAndReplace(string wordtoreplace, string replace)
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(#"C:\invoices\temp.docx", true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
//Regex regexText = new Regex(wordtoreplace);
docText = docText.Replace(wordtoreplace, replace);
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
wordDoc.Close();
}
}
The problem is that the document stream you are opening is an XML document. It contains much more than the words that are typed in your document. There are XML attributes named "name" that are being replaced by your code which make the document no longer validate against the schema.
You can continue doing a plain text replace if you use more unique terms. For example, if your search term is "asdf", then it would be pretty safe to replace because that value won't appear in the XML schema.
To do this correctly, you need to parse the XML document. The XML elements that contain the actual text are named "w:t". If you loop through all of the "w:t" XML elements, you can do your plain text replace on their "InnerText" values. This will guarantee that your XML will remain valid.
Note that you will still have problems if you try to parse the XML directly... If you type your token text ("name" in this case), then apply some kind of format (like bold) to the middle of the word, you will no longer be able to find "name" in a single "w:t" element. By applying the format, the text "name" will be broken up into more than one "w:t" elements. To get this to work in my project, I applied an intermediate step that merged the "w:t" elements before I searched for the tokens. The trick here is knowing when the elements can't be merged due to formatting differences.
I am writing a text into a file. I am getting a column from database and stored it in a string and writing it in a text file. That column contains c# code and it is writing like a single line with small squares for next line(space). I need to write it line by line. Here is my code.
using (var dest = File.AppendText(Path.Combine(_logFolderPath, "a.txt")))
{
dest.WriteLine(line.TrimStart());
}
Any suggestion?
Does Notepad show small squares for new lines, but when you look at the file in Visual Studio it's OK? If so, my guess is that this will fix it:
dest.WriteLine(line.TrimStart().Replace("\n", Environment.NewLine));
try this
File.AppendAllText(Path.Combine(_logFolderPath, "a.txt",
line.Trim() + Environment.NewLine));
dest.WriteLine(line.TrimStart().Replace("\n", Environment.NewLine).Replace("\r", Environment.NewLine));
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.