Appending to new line will not go to new line - c#

I am trying to append the text from a text box to a new line in a text file and have run into an issue. Lets say that there are already contents in the text file and looks something like this
something
Something
Something<---- Cursor ends here
And the cursor ends where the arrow is pointing (After the g on the last 'something'. If I try to use
File.AppendAllLines(#"Location", new[]{tb.Text});
Or
File.AppendAllText(#"Location", tb.Text + Environment.NewLine);
They will put the text where the cursor is at, not on a new line under the last item in the text file. It works if the cursor is on a new line to begin with but as soon as it ends at the end of the word everything goes on the same line.
Is there something I'm missing? Would using a streamwriter or some other method fix this issue?

It does what you should expect. Your text doesn't init with a newline so it is appended just after the point where the previous text ends, To solve your problem you could open the file before writing in it and try to read the last byte.
bool addNewLine = true;
using (FileStream fs = new FileStream(#"location", FileMode.Open))
using (BinaryReader rd = new BinaryReader(fs))
{
fs.Position = fs.Length - 1;
int last = rd.Read();
// The last byte is 10 if there is a LineFeed
if (last == 10)
addNewLine = false;
}
string allLines = (addNewLine ? Environment.NewLine + tb.Text : tb.Text);
File.AppendAllLines(#"Location", new[]{allLines});
As you can see this a bit more complex but this avoid to read all the file in memory.

Actually, as pointed out in other answers. This is by design. File.AppendAllLines appends text at the end of the file. It does not add a line break before appending text. For this, you will have to read the file somehow and determine if the last character is a line break. There are multiple ways to do this.
The simplest way is to just read all lines and check if the last line is empty. If not, just prepend a line break to your string before passing it to File.AppendAllLines.
However, if dealing with large files, or if you do not want to open the file multiple times - something like the following method will do this whilst still only opening the file once.
public void AppendAllLinesAtNewLine(string path, IEnumerable<string> content)
{
// No file, just append as usual.
if (!File.Exists(path))
{
File.AppendAllLines(path, content);
return;
}
using (var stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite))
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
{
// Determines if there is a new line at the end of the file. If not, one is appended.
long readPosition = stream.Length == 0 ? 0 : -1;
stream.Seek(readPosition, SeekOrigin.End);
string end = reader.ReadToEnd();
if (end.Length != 0 && !end.Equals("\n", StringComparison.Ordinal))
{
writer.Write(Environment.NewLine);
}
// Simple write all lines.
foreach (var line in content)
{
writer.WriteLine(line);
}
}
}
Note: the long readPosition = s.Length == 0 ? 0 : -1; is for handling empty files.

This is exactly what you are asking to do. It appends the text you have to the existing file. If that file is 'wrong', the writer can't help it.
You could make sure the line end is always written to the file, if the file is entirely under your control. Else, you could read every line, append yours to it, and write the entire file back. This is bad for large files obviously:
File.WriteAllLines( #"Location"
, File.ReadAllLines(#"Location")
.Concat(new string[] { text })
);

If you put the Environment.NewLine in front of the text, it should give you the results you're looking for:
File.AppendAllText(#"Location", Environment.NewLine + tb.Text);

Thank you all for your suggestions, here is what I decided to do
FileStream stream = new FileStream("location", FileMode.Open, FileAccess.Read);
char actual = '\0';
if(stream.Length != 0)
{
stream.Seek(-1, SeekOrigin.End);
var lastChar = (byte)stream.ReadByte();
actual = (char)lastChar;
}
stream.Close();
try {
if(addCompT.Text != "")
{
if (actual == '\n' || actual == '\0')
File.AppendAllText("location", addCompT.Text + Environment.NewLine);
else
File.AppendAllText("location", Environment.NewLine + addCompT.Text + Environment.NewLine);
addCompT.Text = "";
}
}
catch(System.UnauthorizedAccessException)
{
MessageBox.Show("Please Run Program As Administrator!");
}
I appreciate everyone's help!

Related

How to convert a JDF file to a PDF (Removing text from a multi-encoded document)

I am trying to convert a JDF file to a PDF file using C#.
After looking at the JDF format... I can see that the file is simply an XML placed at the top of a PDF document.
I've tried using the StreamWriter / StreamReader functionality in C# but due to the PDF document also containing binary data, and variable newlines (\r\t and \t) the file produced cannot be opened as some of the binary data is distroyed on the PDF's. Here is some of the code I've tried using without success.
using (StreamReader reader = new StreamReader(_jdf.FullName, Encoding.Default))
{
using (StreamWriter writer = new StreamWriter(_pdf.FullName, false, Encoding.Default))
{
writer.NewLine = "\n"; //Tried without this and with \r\n
bool IsStartOfPDF = false;
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (line.IndexOf("%PDF-") != -1)
{
IsStartOfPDF = true;
}
if (!IsStartOfPDF)
{
continue;
}
writer.WriteLine(line);
}
}
}
I am self answering this question, as it may be a somewhat common problem, and the solution could be informative to others.
As the document contains both binary and text, we cannot simply use the StreamWriter to write the binary back to another file. Even when you use the StreamWriter to read a file then write all the contents into another file you will realize differences between the documents.
You can utilize the BinaryWriter in order to search a multi-part document and write each byte exactly as you found it into another document.
//Using a Binary Reader/Writer as the PDF is multitype
using (var reader = new BinaryReader(File.Open(_file.FullName, FileMode.Open)))
{
using (var writer = new BinaryWriter(File.Open(tempFileName.FullName, FileMode.CreateNew)))
{
//We are searching for the start of the PDF
bool searchingForstartOfPDF = true;
var startOfPDF = "%PDF-".ToCharArray();
//While we haven't reached the end of the stream
while (reader.BaseStream.Position != reader.BaseStream.Length)
{
//If we are still searching for the start of the PDF
if (searchingForstartOfPDF)
{
//Read the current Char
var str = reader.ReadChar();
//If it matches the start of the PDF signiture
if (str.Equals(startOfPDF[0]))
{
//Check the next few characters to see if they match
//keeping an eye on our current position in the stream incase something goes wrong
var currBasePos = reader.BaseStream.Position;
for (var i = 1; i < startOfPDF.Length; i++)
{
//If we found a char that isn't in the PDF signiture, then resume the while loop
//to start searching again from the next position
if (!reader.ReadChar().Equals(startOfPDF[i]))
{
reader.BaseStream.Position = currBasePos;
break;
}
//If we've reached the end of the PDF signiture then we've found a match
if (i == startOfPDF.Length - 1)
{
//Success
//Set the Position to the start of the PDF signiture
searchingForstartOfPDF = false;
reader.BaseStream.Position -= startOfPDF.Length;
//We are no longer searching for the PDF Signiture so
//the remaining bytes in the file will be directly wrote
//using the stream writer
}
}
}
}
else
{
//We are writing the binary now
writer.Write(reader.ReadByte());
}
}
}
}
This code example uses the BinaryReader to read each char 1 by 1 and if it finds a match of the string %PDF- (The PDF Start Signature) it will move the reader position back to the % and then write the remaining document using writer.Write(reader.ReadByte()).

Cut and paste line of text from text file c#

Hi everyone beginner here looking for some advice with a program I'm writing in C#. I need to be able to open a text document, read the first line of text (that is not blank), save this line of text to another text document and finally overwrite the read line with an empty line.
This is what I have so far, everything works fine until the last part where I need to write a blank line to the original text document, I just get a full blank document. Like I mentioned above I'm new to C# so I'm sure there is an easy solution to this but I can't figure it out, any help appreciated:
try
{
StreamReader sr = new StreamReader(#"C:\Users\Stephen\Desktop\Sample.txt");
line = sr.ReadLine();
while (line == "")
{
line = sr.ReadLine();
}
sr.Close();
string path = (#"C:\Users\Stephen\Desktop\new.txt");
if (!File.Exists(path))
{
File.Create(path).Dispose();
TextWriter tw = new StreamWriter(path);
tw.WriteLine(line);
tw.Close();
}
else if (File.Exists(path))
{
TextWriter tw = new StreamWriter(path, true);
tw.WriteLine(line);
tw.Close();
}
StreamWriter sw = new StreamWriter(#"C:\Users\Stephen\Desktop\Sample.txt");
int cnt1 = 0;
while (cnt1 < 1)
{
sw.WriteLine("");
cnt1 = 1;
}
sw.Close();
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
finally
{
Console.WriteLine("Executing finally block.");
}
else
Console.WriteLine("Program Not Installed");
Console.ReadLine();
Unfortunately, you do have to go through the painstaking process of rewriting the file. In most cases, you could get away with loading it into memory and just doing something like:
string contents = File.ReadAllText(oldFile);
contents = contents.Replace("bad line!", "good line!");
File.WriteAllText(newFile, contents);
Remember that you'll have to deal with the idea of line breaks here, since string.Replace doesn't innately pay attention only to whole lines. But that's certainly doable. You could also use a regex with that approach. You can also use File.ReadAllLines(string) to read each line into an IEnumerable<string> and test each one while you write them back to the new file. It just depends on what exactly you want to do and how precise you want to be about it.
using (var writer = new StreamWriter(newFile))
{
foreach (var line in File.ReadAllLines(oldFile))
{
if (shouldInsert(line))
writer.WriteLine(line);
}
}
That, of course, depends on the predicate shouldInsert, but you can modify that as you see so fit. But the nature of IEnumerable<T> should make that relatively light on resources. You could also use a StreamReader for a bit lower-level of support.
using (var writer = new StreamWriter(newFile))
using (var reader = new StreamReader(oldFile))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (shouldInsert(line))
writer.WriteLine(line);
}
}
Recall, of course, that this could leave you with an extra, empty line at the end of the file. I'm too tired to say that with the certainty I should be able to, but I'm pretty sure that's the case. Just keep an eye out for that, if it really matters. Of course, it normally won't.
That all said, the best way to do it would be to have a bit of fun and do it without wasting the memory, by writing a function to read the FileStream in and write out the appropriate bytes to your new file. That's, of course, the most complicated and likely over-kill way, but it'd be a fun undertaking.
See: Append lines to a file using a StreamWriter
Add true to the StreamWriter constructor to set it to "Append" mode. Note that this adds a line at the bottom of the document, so you may have to fiddle a bit to insert or overwrite it at the top instead.
And see: Edit a specific Line of a Text File in C#
Apparently, it's not that easy to just insert or overwrite a single line and the usual method is just to copy all lines while replacing the one you want and writing every line back to the file.

Out of memory exception reading and writing text file

I get an out of memory exception a few seconds after I execute the following code. It doesn't write anything before the exception is thrown. The text file is about half a gigabyte in size. The text file I'm writing too will end up being about 3/4 of a gigabyte. Are there any tricks to navigate around this exception? I assume it's because the text file is too large.
public static void ToCSV(string fileWRITE, string fileREAD)
{
StreamWriter commas = new StreamWriter(fileWRITE);
var readfile = File.ReadAllLines(fileREAD);
foreach (string y in readfile)
{
string q = (y.Substring(0,15)+","+y.Substring(15,1)+","+y.Substring(16,6)+","+y.Substring(22,6)+ ",NULL,NULL,NULL,NULL");
commas.WriteLine(q);
}
commas.Close();
}
I have changed my code to the following yet I still get the same excpetion?
public static void ToCSV(string fileWRITE, string fileREAD)
{
StreamWriter commas = new StreamWriter(fileWRITE);
using (FileStream fs = File.Open(fileREAD, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
string y;
while ((y = sr.ReadLine()) != null)
{
string q = (y.Substring(0, 15) + "," + y.Substring(15, 1) + "," + y.Substring(16, 6) + "," + y.Substring(22, 6) + ",NULL,NULL,NULL,NULL");
commas.WriteLine(q);
}
}
commas.Close();
}
Read the file line by line, it will help you to avoid OutOfMemoryException. And I personnaly prefer using using's to handle streams. It makes sure that the file is closed in case of an exception.
public static void ToCSV(string fileWRITE, string fileREAD)
{
using(var commas = new StreamWriter(fileWRITE))
using(var file = new StreamReader("yourFile.txt"))
{
var line = file.ReadLine();
while( line != null )
{
string q = (y.Substring(0,15)+","+y.Substring(15,1)+","+y.Substring(16,6)+","+y.Substring(22,6)+ ",NULL,NULL,NULL,NULL");
commas.WriteLine(q);
line = file.ReadLine();
}
}
}
In the following post you can find numerous methods for reading and writing large files. Reading large text files with streams in C#
Basically you just need to read the bytes in a buffer which will be reused. This way you will load a very small amount of the file into memory.
Instead of reading the whole file, try to read and process line by line.
That way you do not risk to run into an out of memory exception. Because even if you succeed in organising more memory for the program, one day will come where the file will again be too large.
But the program may loose speed if you use less memory, so basically you'd have to balance the memory use and the execution time. One workaround would be to use a buffered output, reading more than one line at a time or transforming the strings in multiple threads.

How to print out text from a text file on multiple lines

I have a list box that will display some info from a txt file. However, I can't seem to print out the info on different lines. Here's the snippet. The text should be displayed when user presses a button.
using (StreamReader sr = new StreamReader("Books.txt"))
{
String line = sr.ReadToEnd();
listBox1.Items.Add(line + "\n");
}
There are 10 lines in the file.
You can use File.ReadAllLines documented at http://msdn.microsoft.com/en-us/library/system.io.file.readalllines.aspx.
Example of usage is provided at http://msdn.microsoft.com/en-us/library/s2tte0y1.aspx
In your example:
var lines = File.ReadAllLines("Book.txt");
foreach (var element in lines)
{
listBox1.Items.Add(element);
}
You can also do one liner.
listBox1.Items.AddRange(File.ReadAllLines("Book.txt")); // tinstaafl's comment
ReadToEnd() reads everything in the file into one variable.
What you want is ReadLine().
This is one way that should work (though it can probably be done better).
using (StreamReader sr = new StreamReader("Books.txt"))
{
while(true)
{
String line = sr.ReadLine();
if(line==null)
break;
listBox1.Items.Add(line + "\n");
}
}
See the documentation for StreamReader.
By using StreamReader.ReadToEnd() you are putting the whole content of the file in a single string.
To add a Item to the ListBox for each line in the file this should work:
using (StreamReader sr = new StreamReader("Books.txt"))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
listBox1.Items.Add(line);
}
}

c# saving textbox.text to txt file. txt file doesn't recognize end of line character

I have the following code:
void AppendText(string txt)
{
txt = txt + "\r\n";
Textbox1.AppendText(txt);
Textbox1.Select(Textbox1.Text.Length,0);
}
//....
void someFunction()
{
//...
string log = #"C:\log.txt";
using (FileStream fs = new FileStream(log, FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write(Textbox1.Text);
}
}
//...
}
The problem is in Textbox1.Text field in the form, "\r\n" works fine, but when I copy the Textbox1.Text to log.txt, the log.txt doesn't have new line where it's supposed to be. Instead there's a strange charater like this "[]" where "\r\n" is. I think problem lies in the sw.Write(tbox.text) right? But I don't know how to fix it. Could anyone give me a hand? Help is really appreciated. Thanks in advance.
My guess would be that the Textbox creates unicode characters (two bytes per character).
In what format are you reading the data? ASCII unicode UTF?
If I remember correctly /n/r is an old trick to write a newline character to the string but in what format and what does it mean? Environment.Newline is much better and would work on windows mobile/unix builds too.
I usually create a class level variable called br with environment.newline as its content, creates much shorter code.
You should do like this.
string log = #"C:\log.txt";
using (FileStream fs = new FileStream(log, FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(fs))
{
foreach(string line in Textbox1.Lines)
sw.Write(line+sw.NewLine);
}
}
Your code is correct. Just add sw.Close(); after sw.Write(Textbox1.Text);

Categories

Resources