Streamwriter and Streamreader - c#-4.0

I have my uni assignment and it's only very basic coding but I have to do
A user shall be able to store records to a file. On start-up a user shall be able to select a file of records and load these into the program.
I am having trouble with this as it will save but once I close the program and re-open it they are gone, any ones help is appreciated.
This is what I have so far:
private void Save_Click(object sender, EventArgs e)
{
SaveToFile(records, file);
}
private void SaveToFile(List<Client> records, string file)
{
//File.WriteAllText(file, String.Empty);
StreamWriter writer = new StreamWriter(file);
StreamReader reader = new StreamReader(file);
try
{
AddMember();
for (int i = 0; i < records.Count; i++)
{
writer.WriteLine(records[i].WriteToFile());
}
writer.Close();
}
catch (IOException z)
{
MessageBox.Show("Error" + z);
}
}

Before closing the StreamWriter you should call Flush() method. Flush() Clears all buffers for the current writer and causes any buffered data to be written to the underlying stream.

reader.clos();
you forgot this

This is just a guess, but it sounds like you might be overwriting the file when you start the program.
In your SaveToFile method, you have the following two lines at the start:
StreamWriter writer = new StreamWriter(file);
StreamReader reader = new StreamReader(file);
The first one will create a new file with the name in file. The second one isn't needed if you're not doing any reading from the file.
Now, if you have a similar block of code in somewhere else in your program that is executed before the SaveToFile method is called, it will overwrite the file (and since you most likely don't write anything in that earlier part of the code, you're left with a blank file).
To prevent this, there are two suggestions I'll offer:
Only create a StreamWriter when you are going to be writing to the file. Any other times you create a StreamWriter, you will be overwriting the existing file.
If you don't want to overwrite the file, you can use the overload of the constructor that takes a second parameter (a boolean) to indicate whether or not to append new data to the file:
StreamWriter writer = new StreamWriter(file, true);
Additionally, I'd suggest getting to know and use using blocks, as this will take care of closing and flushing the StreamWriter (and its underlying stream) for you, even if an exception occurs and is unhandled:
private void SaveToFile(List<Client> records, string file)
{
try
{
AddMember();
// If you don't want to append but overwrite, use:
// using (StreamWriter writer = new StreamWriter(file))
using (StreamWriter writer = new StreamWriter(file, append))
{
for (int i = 0; i < records.Count; i++)
{
writer.WriteLine(records[i].WriteToFile());
}
}
}
catch (IOException z)
{
MessageBox.Show("Error" + z);
}
}

Related

How to avoid extra line feeds in MIME export?

I'm exporting MIME eMails with the following code:
public String fromRawMime(final Session s, final Document doc) throws NotesException {
final Stream notesStream = s.createStream();
final MIMEEntity rootMime = doc.getMIMEEntity();
// check if it is multi-part or single
if (rootMime.getContentType().equals("multipart")) {
this.printMIME(rootMime, notesStream);
} else {
// We can just write the content into the
// Notes stream to get the bytes
rootMime.getEntityAsText(notesStream);
}
// Write it out
notesStream.setPosition(0);
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.append(notesStream.read());
notesStream.close();
notesStream.recycle();
rootMime.recycle();
return out.toString();
}
// Write out a mime entry to a Stream object, includes sub entries
private void printMIME(final MIMEEntity mimeRoot, final Stream out) throws NotesException {
if (mimeRoot == null) {
return;
}
// Encode binary as base64
if (mimeRoot.getEncoding() == MIMEEntity.ENC_IDENTITY_BINARY) {
mimeRoot.decodeContent();
mimeRoot.encodeContent(MIMEEntity.ENC_BASE64);
}
out.writeText(mimeRoot.getBoundaryStart(), Stream.EOL_NONE);
mimeRoot.getEntityAsText(out);
out.writeText(mimeRoot.getBoundaryEnd(), Stream.EOL_NONE);
if (mimeRoot.getContentType().equalsIgnoreCase("multipart")) {
// Print preamble if it isn't empty
final String preamble = mimeRoot.getPreamble();
if (!preamble.isEmpty()) {
out.writeText(preamble, Stream.EOL_NONE);
}
// Print content of each child entity - recursive calls
// Include recycle of mime elements
MIMEEntity mimeChild = mimeRoot.getFirstChildEntity();
while (mimeChild != null) {
this.printMIME(mimeChild, out);
final MIMEEntity mimeNext = mimeChild.getNextSibling();
// Recycle to ensure we don't bleed memory
mimeChild.recyle();
mimeChild = mimeNext;
}
}
}
The result contains one empty line for each line. Including the content that gets added using getEntityAsText. What am I missing to get rid of the extra lines?
The email RFCs require the use of CRLF to terminate text lines.
You are using EOL_NONE, so the writeText method isn't adding anything to the text, but apparently both the CR and LF are being treated as newlines in your output. You may want to try using out.writeText with EOL_PLATFORM instead.
The devils is in the details...
the printMIME function works just fine. Changing the EOL didn't have an impact. However I added EOL_PLATFORM later on for the final result to separate the headers from the content.
The offending code is this:
notesStream.setPosition(0);
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.append(notesStream.read());
notesStream.close();
Turns out that it seems to interpret whatever was in the MIME as 2 line feeds. So the code needs to be changed to:
notesStream.setPosition(0);
String out = notesStream.readText();
notesStream.close();
so instead of a OutputStream I needed a String and instead of read() I needed readText(). Now working happily in my "project castle"

BufferedReader is sometimes empty

I have Loader class where I load txt file into BufferedReader from resources and return this field. I use this method but it acts really strange(for me). When I don't put
String str = bufferReader.readLine(); after
bufferReader = new BufferedReader(fileReader);
(in Loader class) than bufferReader in another class is empty, and readLine() returns null. When I write that piece of code in Loader class, I can read each line from txt, except the 1. one which is read in Loader class. Also, I can't read last line if I dont put enter at the end.
public BufferedReader loadFromFileToBufferReader(String fileName) {
ClassLoader classLoader = getClass().getClassLoader();
System.out.print(getClass().getClassLoader().getResource("resources/" + fileName));
File file = new File(classLoader.getResource("resources/" + fileName).getFile());
BufferedReader bufferReader = null;
try (FileReader fileReader = new FileReader(file)) {
bufferReader = new BufferedReader(fileReader);
String str = bufferReader.readLine();
} catch (IOException e) {
System.err.println("Something went terribly wrong with file reading");
}
return bufferReader;
}
and usage:
public Database() {
productsInDatabse = new ArrayList<>();
codesList = new ArrayList<>();
loader = new LoadFromFile();
BufferedReader output = loader.loadFromFileToBufferReader("database.txt");
Product product;
String line;
String[] array;
try {
line = output.readLine();
while (line != null) {
You should paste your code here because it's hard to deduce all the possible causes of this without seeing the code on 100% but I am guessing you have it the same file open at the same time from multiple sources without closing it before from one? Could be literally millions of little things, just telling you how the same error happened to me.

.NET 4.0 BackgroundWorker class and unusual behavior

I am running into some strange behavior in the backgroundworker class that leads me to believe that I don't fully understand how it works. I assumed that the following code sections were more or less equal except for some extra features that the BackgroundWorker implements (like progress reporting, etc.):
section 1:
void StartSeparateThread(){
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
//Execute some code asynchronous to the thread that owns the function
//StartSeparateThread() but synchronous to itself.
var SendCommand = "SomeCommandToSend";
var toWaitFor = new List<string>(){"Various","Possible","Outputs to wait for"};
var SecondsToWait = 30;
//this calls a function that sends the command over the NetworkStream and waits
//for various responses.
var Result=SendAndWaitFor(SendCommand,toWaitFor,SecondsToWait);
}
Section 2:
void StartSeparateThread(){
Thread pollThread = new Thread(new ThreadStart(DoStuff));
pollThread.Start();
}
void DoStuff(object sender, DoWorkEventArgs e)
{
//Execute some code asynchronous to the thread that owns the function
//StartSeparateThread() but synchronous to itself.
var SendCommand = "SomeCommandToSend";
var toWaitFor = new List<string>(){"Various","Possible","Outputs to wait for"};
var SecondsToWait = 30;
//this calls a function that sends the command over the NetworkStream and waits
//for various responses.
var Result=SendAndWaitFor(SendCommand,toWaitFor,SecondsToWait);
}
I was using Section 1 to run some code that sent a string over a networkstream and waited for a desired response string, capturing all output during that time. I wrote a function to do this that would return the networkstream output, the index of the the sent string, as well as the index of the desired response string. I was seeing some strange behavior with this so I changed the function to only return when both the send string and the output string were found, and that the index of the found string was greater than the index of the sent string. It would otherwise loop forever (just for testing). I would find that the function would indeed return but that the index of both strings were -1 and the output string was null or sometimes filled with the expected output of the previous call. If I were to make a guess about what was happening, it would be that external functions called from within the bw_DoWork() function are run asynchronously to the thread that owns the bw_DoWork() function. As a result, since my SendAndWaitFor() function was called multiple times in succession. the second call would be run before the first call finished, overwriting the results of the first call after they were returned but before they could be evaluated. This seems to make sense because the first call would always run correctly and successive calls would show the strange behavior described above but it seems counter intuitive to how the BackgroundWorker class should behave. Also If I were to break within the SendAndWaitFor function, things would behave properly. This again leads me to believe there is some multi-threading going on within the bwDoWork function itself.
When I change the code in the first section above to the code of the second section, things work entirely as expected. So, can anyone who understands the BackgroundWorker class explain what could be going on? Below are some related functions that may be relevant.
Thanks!
public Dictionary<string, string> SendAndWaitFor(string sendString, List<string> toWaitFor, int seconds)
{
var toReturn = new Dictionary<string, string>();
var data = new List<byte>();
var enc = new ASCIIEncoding();
var output = "";
var FoundString = "";
//wait for current buffer to clear
output = this.SynchronousRead();
while(!string.IsNullOrEmpty(output)){
output = SynchronousRead();
}
//output should be null at this point and the buffer should be clear.
//send the desired data
this.write(enc.GetBytes(sendString));
//look for all desired strings until timeout is reached
int sendIndex=-1;
int foundIndex = -1;
output += SynchronousRead();
for (DateTime start = DateTime.Now; DateTime.Now - start < new TimeSpan(0, 0, seconds); )
{
//wait for a short period to allow the buffer to fill with new data
Thread.Sleep(300);
//read the buffer and add it to the output
output += SynchronousRead();
foreach (var s in toWaitFor)
{
sendIndex = output.IndexOf(sendString);
foundIndex = output.LastIndexOf(s);
if (foundIndex>sendIndex)
{
toReturn["sendIndex"] = sendIndex.ToString();
toReturn["foundIndex"] = sendIndex.ToString();
toReturn["Output"] = output;
toReturn["FoundString"] = s;
return toReturn;
}
}
}
//Set this to loop infinitely while debuging to make sure the function was only
//returning above
while(true){
}
toReturn["sendIndex"]="";
toReturn["foundIndex"]="";
toReturn["Output"] =output;
toReturn["FoundString"] = "";
return toReturn;
}
public void write(byte[] toWrite)
{
var enc = new ASCIIEncoding();
var writeString = enc.GetString(toWrite);
var ns = connection.GetStream();
ns.Write(toWrite, 0, toWrite.Length);
}
public string SynchronousRead()
{
string toReturn = "";
ASCIIEncoding enc = new ASCIIEncoding();
var ns = connection.GetStream();
var sb = new StringBuilder();
while (ns.DataAvailable)
{
var buffer = new byte[4096];
var numberOfBytesRead = ns.Read(buffer, 0, buffer.Length);
sb.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, numberOfBytesRead));
toReturn += sb.ToString();
}
return toReturn;
}
All data to be used by a background worker should be passed in through the DoWorkEventArgs and nothing should be pulled off of the class (or GUI interface).
In looking at your code I could not identify where the property(?) connnection was being created. My guess is that connection is created on a different thread, or may be pulling read information, maybe from a GUI(?) and either one of those could cause problems.
I suggest that you create the connection instance in the dowork event and not pull an existing one off of a different thread. Also verify that the data connection works with does not access any info off of a GUI, but its info is passed in as its made.
I discuss an issue with the Background worker on my blog C# WPF: Linq Fails in BackgroundWorker DoWork Event which might show you where the issue lies in your code.

Add a string property to a linklabel?

I am currently making an "app launcher" which reads a text file line by line. Each line is a path to a useful program somewhere else on my pc. A link label is automatically made for each path (i.e. each line) in the text file.
I would like the .Text property of the link label to be an abbreviated form of the path (i.e. just the file name, not the whole path). I have found out how to shorten the string in this way (so far so good !)
However, I would also like to store the full path somewhere - as this is what my linklabel will need to link to. In Javascript I could pretty much just add this property to linklabel like so: mylinklabel.fullpath=line; (where line is the current line as we read through the text file, and fullpath is my "custom" property that I would like to try and add to the link label. I guess it needs declaring, but I am not sure how.
Below is the part of my code which creates the form, reads the text file line by line and creates a link label for the path found on each line:
private void Form1_Load(object sender, EventArgs e) //on form load
{
//System.Console.WriteLine("hello!");
int counter = 0;
string line;
string filenameNoExtension;
string myfile = #"c:\\users\matt\desktop\file.txt";
//string filenameNoExtension = Path.GetFileNameWithoutExtension(myfile);
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(myfile);
while ((line = file.ReadLine()) != null)
{
//MessageBox.Show(line); //check whats on each line
LinkLabel mylinklabel = new LinkLabel();
filenameNoExtension = Path.GetFileNameWithoutExtension(line); //shortens the path to just the file name without extension
mylinklabel.Text = filenameNoExtension;
//string fullpath=line; //doesn't work
//mylinklabel.fullpath=line; //doesn't work
mylinklabel.Text = filenameNoExtension; //displays the shortened path
this.Controls.Add(mylinklabel);
mylinklabel.Location = new Point(0, 30 + counter * 30);
mylinklabel.AutoSize = true;
mylinklabel.VisitedLinkColor = System.Drawing.Color.White;
mylinklabel.LinkColor = System.Drawing.Color.White;
mylinklabel.Click += new System.EventHandler(LinkClick);
counter++;
}
file.Close();
}
So, how can I store a full path as a string inside the linklabel for use in my onclick function later on?
You could derive a new custom class or you could use a secondary data store for your additional info the easiest solution would be to use a dictionary.
dictonary<string,string> FilePaths = new dictonary<string,string>();
private void Form1_Load(object sender, EventArgs e) //on form load
{
...
FilePath[filenameNoExtension] = line;
}
You Can Access the Path
FilePath[mylinklabel.Tex]
One option you have is to have a method that truncates your string (and even adds "..."). You can then store the full path in the Tag property of the Linklabel. And here's an example of the first part (truncating the text).
public static string Truncate(this string s, int maxLength)
{
if (string.IsNullOrEmpty(s) || maxLength <= 0)
return string.Empty;
else if (s.Length > maxLength)
return s.Substring(0, maxLength) + "...";
else
return s;
}
Hope that helps some

Console application: How to update the display without flicker?

Using C# 4 in a Windows console application that continually reports progress how can I make the "redraw" of the screen more fluid?
I'd like to do one of the following:
- Have it only "redraw" the part of the screen that's changing (the progress portion) and leave the rest as is.
- "Redraw" the whole screen but not have it flicker.
Currently I re-write all the text (application name, etc.). Like this:
Console.Clear();
WriteTitle();
Console.WriteLine();
Console.WriteLine("Deleting:\t{0} of {1} ({2})".FormatString(count.ToString("N0"), total.ToString("N0"), (count / (decimal)total).ToString("P2")));
Which causes a lot of flickering.
Try Console.SetCursorPosition. More details here: How can I update the current line in a C# Windows Console App?
static void Main(string[] args)
{
Console.SetCursorPosition(0, 0);
Console.Write("################################");
for (int row = 1; row < 10; row++)
{
Console.SetCursorPosition(0, row);
Console.Write("# #");
}
Console.SetCursorPosition(0, 10);
Console.Write("################################");
int data = 1;
System.Diagnostics.Stopwatch clock = new System.Diagnostics.Stopwatch();
clock.Start();
while (true)
{
data++;
Console.SetCursorPosition(1, 2);
Console.Write("Current Value: " + data.ToString());
Console.SetCursorPosition(1, 3);
Console.Write("Running Time: " + clock.Elapsed.TotalSeconds.ToString());
Thread.Sleep(1000);
}
Console.ReadKey();
}
I know this question is a bit old but I found if you set Console.CursorVisible = false then the flickering stops as well.
Here's a simple working demo that shows multi-line usage without flickering. It shows the current time and a random string every second.
private static void StatusUpdate()
{
var whiteSpace = new StringBuilder();
whiteSpace.Append(' ', 10);
var random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var randomWord = new string(Enumerable.Repeat(chars, random.Next(10)).Select(s => s[random.Next(s.Length)]).ToArray());
while (true)
{
Console.SetCursorPosition(0, 0);
var sb = new StringBuilder();
sb.AppendLine($"Program Status:{whiteSpace}");
sb.AppendLine("-------------------------------");
sb.AppendLine($"Last Updated: {DateTime.Now}{whiteSpace}");
sb.AppendLine($"Random Word: {randomWord}{whiteSpace}");
sb.AppendLine("-------------------------------");
Console.Write(sb);
Thread.Sleep(1000);
}
}
The above example assumes your console window is blank to start. If not, make sure to use Console.Clear() first.
Technical Note:
SetCursorPosition(0,0) places the cursor back to the top (0,0) so the next call to Console.Write will start from line 0, char 0. Note, it doesn't delete the previous content before writing. As an example, if you write "asdf" over a previous line such as "0123456", you'll end up with something like "asdf456" on that line. For that reason, we use a whiteSpace variable to ensure any lingering characters from the previous line are overwritten with blank spaces. Adjust the length of the whiteSpace variable to meet your needs. You only need the whiteSpace variable for lines that change.
Personal Note:
For my purposes, I wanted to show the applications current status (once a second) along with a bunch of other status information and I wanted to avoid any annoying flickering that can happen when you use Console.Clear(). In my application, I run my status updates behind a separate thread so it constantly provides updates even though I have numerous other threads and long running tasks going at the same time.
Credits:
Thanks to previous posters and dtb for the random string generator used in the demo.
How can I generate random alphanumeric strings in C#?
You could try to hack something together using the core libraries.
Rather than waste your time for sub-standard results, I would check out this C# port of the ncurses library (which is a library used for formatting console output):
Curses Sharp
I think you can use \r in Windows console to return the beginning of a line.
You could also use SetCursorPosition.
I would recommend the following extension methods. They allow you to use a StringBuilder to refresh the console view without any flicker, and also tidies up any residual characters on each line
The Problem: The following demo demonstrates using a standard StringBuilder, where updating lines that are shorter than the previously written line get jumbled up. It does this by writing a short string, then a long string on a loop:
public static void Main(string[] args)
{
var switchTextLength = false;
while(true)
{
var sb = new StringBuilder();
if (switchTextLength)
sb.AppendLine("Short msg");
else
sb.AppendLine("Longer message");
sb.UpdateConsole();
switchTextLength = !switchTextLength;
Thread.Sleep(500);
}
}
Result:
The Solution: By using the extension method provided below, the issue is resolved
public static void Main(string[] args)
{
var switchTextLength = false;
while(true)
{
var sb = new StringBuilder();
if (switchTextLength)
sb.AppendLineEx("Short msg");
else
sb.AppendLineEx("Longer message");
sb.UpdateConsole();
switchTextLength = !switchTextLength;
Thread.Sleep(500);
}
}
Result:
Extension Methods:
public static class StringBuilderExtensions
{
/// <summary>
/// Allows StrinbBuilder callers to append a line and blank out the remaining characters for the length of the console buffer width
/// </summary>
public static void AppendLineEx(this StringBuilder c, string msg)
{
// Append the actual line
c.Append(msg);
// Add blanking chars for the rest of the buffer
c.Append(' ', Console.BufferWidth - msg.Length - 1);
// Finish the line
c.Append(Environment.NewLine);
}
/// <summary>
/// Combines two StringBuilders using AppendLineEx
/// </summary>
public static void AppendEx(this StringBuilder c, StringBuilder toAdd)
{
foreach (var line in toAdd.ReadLines())
{
c.AppendLineEx(line);
}
}
/// <summary>
/// Hides the console cursor, resets its position and writes out the string builder
/// </summary>
public static void UpdateConsole(this StringBuilder c)
{
// Ensure the cursor is hidden
if (Console.CursorVisible) Console.CursorVisible = false;
// Reset the cursor position to the top of the console and write out the string builder
Console.SetCursorPosition(0, 0);
Console.WriteLine(c);
}
}
I actually had this issue so I made a quick simple method to try and eliminate this.
static void Clear(string text, int x, int y)
{
char[] textChars = text.ToCharArray();
string newText = "";
//Converts the string you just wrote into a blank string
foreach(char c in textChars)
{
text = text.Replace(c, ' ');
}
newText = text;
//Sets the cursor position
Console.SetCursorPosition(x, y);
//Writes the blank string over the old string
Console.WriteLine(newText);
//Resets cursor position
Console.SetCursorPosition(0, 0);
}
It actually worked surprisingly well and I hope it may work for you!
Naive approach but for simple applications is working:
protected string clearBuffer = null; // Clear this if window size changes
protected void ClearConsole()
{
if (clearBuffer == null)
{
var line = "".PadLeft(Console.WindowWidth, ' ');
var lines = new StringBuilder();
for (var i = 0; i < Console.WindowHeight; i++)
{
lines.AppendLine(line);
}
clearBuffer = lines.ToString();
}
Console.SetCursorPosition(0, 0);
Console.Write(clearBuffer);
Console.SetCursorPosition(0, 0);
}
Console.SetCursorPosition(0, 0); //Instead of Console.Clear();
WriteTitle();
Console.WriteLine();
Console.WriteLine("Deleting:\t{0} of {1} ({2})".FormatString(count.ToString("N0")

Resources