How to Write to a file using StreamWriter? - c#

in my Wpf app I'm using a class Person (that is a base class), and that contains a virtual method SaveData(), and other class Client that inherits from Person. How to override method SaveData() and keeping data from base?
Class Person
public virtual void SaveData()
{
string arqName = string.Format("Person{0}" + ".txt", Id);
StreamWriter file = new StreamWriter(arqNome);
file.WriteLine("ID: " + Id);
file.WriteLine("DOB: " + dOB);
file.WriteLine("Name: " + name);
file.WriteLine("Age: " + age);
file.Flush();
file.Close();
}
Class Client
public override void SaveData()
{
base.SaveData();
string arqName = string.Format("Person{0}" + ".txt", Id);
StreamWriter file = new StreamWriter(arqNome);
file.WriteLine("Cod: " + cod);
file.WriteLine("Credits: " + credits);
file.Flush();
file.Close();
}
The override method in Client is indeed override others data as Name, Age, DOB... I need to mantains both in same file.

StreamWriter is stream decorator, so you better instantiate FileStream and pass it to the StreamWriter constructor. Thus you can customize it. Append mode opens file and moves pointer to the end of file, so the next thing you write will be appended. And use using directive insted of explicitly calling Close():
Person class SaveData():
using (var fileStream = new FileStream(String.Format("Person{0}.txt", Id), FileMode.OpenOrCreate))
using (var streamWriter = new StreamWriter(fileStream))
{
streamWriter.WriteLine("ID: " + Id);
streamWriter.WriteLine("DOB: " + dOB);
streamWriter.WriteLine("Name: " + name);
streamWriter.WriteLine("Age: " + age);
}
Client class SaveData():
base.SaveData();
using (var fileStream = new FileStream(String.Format("Person{0}.txt", Id), FileMode.Append))
using (var streamWriter = new StreamWriter(fileStream))
{
streamWriter.WriteLine("Cod: " + cod);
streamWriter.WriteLine("Credits: " + credits);
}

You should split it into 2 methods: SaveData() and WriteData(StreamWriter file). SaveData creates the stream and then calls WriteData. Then you override only the WriteDate method, calling the base.

AlexDev's answer is correct. But if you can't alter Person code (and given that you store data per file) you can use 'append' flag to add data into existed file.
But it's not the best idea:
StreamWriter file = new StreamWriter(arqNome, append: true);

Related

How to add all list student items in file using interface?

Hello I'm trying to add a list in a file using interface, but I can add only last item of list in it? Whats wrong?
I think I'm ok with interface.
//interface
interface IRuajtshem
{
void Ruaj();
}
I think here is the problem.
//class
public class Student : IRuajtshem
{
protected int ID;
protected string emri;
protected string mbiemri;
...
...
...
public void Ruaj()
{
string path = #"C:\\...\\...\\text.txt";
if (File.Exists(path))
{
File.Delete(path);
}
else if (!File.Exists(path))
File.Create(path).Close();
var f = File.AppendText(path);
f.WriteLine(Studenti + " " + Studentii + " " + Studentiii);
f.Close();
}
}
And finally the list ...
//#Main()
List<Student> student = new List<Student>()
{
new Student(1, "Name", "Surname"),
new Student(2, "name", "Surname"),
new Student(3, "Name", "surname"),
new Student(4, "name", "surname")
};
foreach (Student st in student)
{
st.Ruaj();
Console.WriteLine();
}
You keep deleting and recreating the file. Try this instead:
public void Ruaj()
{
string path = #"C:\\...\\...\\text.txt";
using (var f = File.AppendText(path))
{
f.WriteLine(Studenti + " " + Studentii + " " + Studentiii);
}
}
This is the part of your code that kept "resetting" the file:
if (File.Exists(path))
{
File.Delete(path); // deletes file if it exists
}
else if (!File.Exists(path))
File.Create(path).Close(); // creates empty file if doesnt exist
And I think that creating an empty file is unneeded as well, because AppendText will create the file for you if it doesn't exist, and not throw an error:
Creates a StreamWriter that appends UTF-8 encoded text to an existing file, or to a new file if the specified file does not exist.
From here.
Another method you might want to check out is AppendAllText which gets a path and a string, and does all the dirty work for you in one line. Just need to make sure your string ends with "\r\n" if you ever want a line break.
This is because you are deleting the file if it exists:
if (File.Exists(path))
{
File.Delete(path);
}
You should open the file instead of deleting it.

Not able to write a Text on txt File using C#

I have tried to write a string on text file,but its not writing anything and there is no exceptions. My code is:
public void CreateLog(string sLogInfo)
{
string sDestionation = null;
string sFileName = DateTime.Now.ToString("yyyyMMdd") + "_log.txt";
sDestionation = #"D:\Log\";
//sDestionation = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + ConfigurationManager.AppSettings["DestinationPath"].ToString();
string sFile = sDestionation + sFileName;
if (!System.IO.Directory.Exists(sDestionation))
{
System.IO.Directory.CreateDirectory(sDestionation);
}
StreamWriter oWriter = null;
if (!System.IO.File.Exists(sFile))
{
oWriter = File.CreateText(sFile);
}
else
{
oWriter = File.AppendText(sFile);
}
oWriter.WriteLine(DateTime.Now.ToString() + ": " + sLogInfo.Trim());
}
StreamWriter is IDisposable object. You should dispose it after using. For this you can use using statement like this:
public void CreateLog(string sLogInfo)
{
string sDestionation = null;
string sFileName = DateTime.Now.ToString("yyyyMMdd") + "_log.txt";
sDestionation = #"D:\Log\";
var sFile = sDestionation + sFileName;
if (!Directory.Exists(sDestionation))
{
Directory.CreateDirectory(sDestionation);
}
using (var oWriter = new StreamWriter(sFile, true))
oWriter.WriteLine(DateTime.Now + ": " + sLogInfo.Trim());
}
Use File.AppendAllText that will do all the steps (except creating folder) for you.
Otherwise you should properly dispose writer when you are done, preferably with using in the same function:
using(oWriter)
{
oWriter.WriteLine(DateTime.Now.ToString() + ": " + sLogInfo.Trim());
}
Your code looks fine, however, I think you should add at the end of it the following:
oWriter.Close()
You should flush (disposing is enough) your data into the file at the end of your code:
oWriter.Flush(); //Save (Clears all buffers for the current writer and causes any buffered data to be written to the underlying stream.)
oWriter.Dispose(); //Then free this resource
As Yuval mentioned looking at C#'s StreamWriter.cs class it does indeed calls the Flush method internally. See here: Reference

Why do I have an IOException in this case?

I'm programming a video player in C# (the video works fine) and what I need now is to get the libvlc logs as well as my custom logs to print them in a file.
I use NLog which handles the libvlc logs (with nVLC) and I raise an event for my custom logs, and in buth cases this function is called :
private static void tracerlogs(string erreur, VLCControl.ControleUtilisateurVLC.LogLevels LvLog)
{
string path = "logs.txt";//Sera redéfini dans l'appli
if (!File.Exists(path))
{
// Create a file to write to.
using (StreamWriter sw = File.CreateText(path))
{
sw.WriteLine(erreur + " " + LvLog.ToString());
sw.Close();
}
}
else
{
using (StreamWriter sw = File.AppendText(path))
{
sw.WriteLine(erreur + " " + LvLog.ToString());
sw.Close();
}
}
Console.WriteLine(erreur + " " + LvLog.ToString());
}
The problem is that I'm getting at random times a System.IO.IOException telling that "the process cannot access the file because it is being used by another process". Although I do close my StreamWriter (which should normally not be useful in a using block)... This makes my app crash. Does anyone have any idea why it does this ?
I finally solved it by adding a resource : as there was a conflict between different threads trying to access this function, I wrapped this :
private static void tracerlogs(string erreur, VLCControl.ControleUtilisateurVLC.LogLevels LvLog)
{
lock (LockLog) {
string path = "logs.txt";//Sera redéfini dans l'appli
if (!File.Exists(path))
{
// Create a file to write to.
using (StreamWriter sw = File.CreateText(path))
{
sw.WriteLine(erreur + " " + LvLog.ToString());
sw.Close();
}
}
else
{
using (StreamWriter sw = File.AppendText(path))
{
sw.WriteLine(erreur + " " + LvLog.ToString());
sw.Close();
}
}
Console.WriteLine(erreur + " " + LvLog.ToString());
}
}
And I declare a public static readonly object LockLog = new Object(); in my class. This works just fine ! Thanks to those who told me that this had to see with threading.

StreamWriter won't write to log file

This code will create "output.txt" in C:\temp if it doesn't already exist. However, log.WriteLine(); doesn't work for me. When I open the file, I don't see it. Why is this?
private static string LogFile = #"C:\Temp\output.txt";
private StreamWriter log;
if (!File.Exists(#"" + LogFile))
{
log = new StreamWriter(#"" + LogFile);
}
else {
log = File.AppendText(#"" + LogFile);
}
log.WriteLine("["+DateTime.Now + "]: ");
You need to close the StreamWriter. It's best to use a using block for this, as it guarantees that the StreamWriter will be closed, even if an exception is thrown.
using (var log = GetLog()){
log.WriteLine("["+DateTime.Now + "]: ");
}
...
public StreamWriter GetLog(){
if (!File.Exists(#"" + LogFile))
{
return new StreamWriter(#"" + LogFile);
}
else {
return File.AppendText(#"" + LogFile);
}
}
Just a little improvement in code to #John Saunders answer.
using (var log = GetLog())
{
log.WriteLine("["+DateTime.Now + "]: ");
}
...
public StreamWriter GetLog()
{
return new StreamWriter(LogFile, File.Exists(LogFile));
}
The second parameter StreamWriter constructer takes determines append operation. Thus if file exists append otherwise not will do it. I think this is neater. And actually you can even do:
using (var log = new StreamWriter(LogFile, true))
{
log.WriteLine("["+DateTime.Now + "]: ");
}
Always appends, and if file does not exist creates it.
If you are always appending the same thing to the file whether or not it already exists, you don't need the conditional.
File.AppendText will create the file if it doesn't exist.
private static string LogFile = #"C:\Temp\output.txt";
using (StreamWriter sw = File.AppendText(LogFile))
{
sw.WriteLine("["+DateTime.Now + "]: ");
}
As John Saunders already said, you need to Dispose the stream writer, which will be done by putting it in a using statement.
(Documentation for StreamWriter)

Disposing File Object Properly

Ok so heres the thing. When ever a trigger is hit i append my logs in a specific folder. The code works fine and it appends it correctly but if i try to manually delete the folder from the desktop its giving a "The action cannot be completed cause the folder/file is open in another program";
i guess im not disposing it right but i dont know where i missed it. I know its the folder that is attached to the process cause i tried to delete the .log file inside and it allowed me.
private void LogEvent(string filename,bool AppendTxt,string msg)
{
string sLogFormat = DateTime.Now.ToShortDateString().ToString() + " " + DateTime.Now.ToLongTimeString().ToString() + " ==> ";
msg = sLogFormat + msg;
// create directory
if (System.IO.Directory.Exists("C:\\Users\\DT-Npax\\Desktop\\LOGS1") != true)
{
Directory.CreateDirectory("C:\\Users\\DT-Npax\\Desktop\\LOGS1");
}
string dailyLog = "C:\\Users\\DT-Npax\\Desktop\\LOGS1" + "\\" + filename + ".log";
FileStream FS = null;
//write or append txt
if (!AppendTxt)
{
if (File.Exists(dailyLog))
{
File.Delete(dailyLog);
}
using (FS = File.Create(dailyLog)) { }
FS.Close();
StreamWriter TXT_WRITE = new StreamWriter(dailyLog);
TXT_WRITE.WriteLine(msg);
TXT_WRITE.Close();
}
else
{
if (!File.Exists(dailyLog))
{
using (FS = File.Create(dailyLog)) { }
FS.Close();
}
FileStream FSAppend = new FileStream(dailyLog, FileMode.Append, FileAccess.Write);
StreamWriter TXT_WRITE = new StreamWriter(FSAppend);
TXT_WRITE.WriteLine(msg);
TXT_WRITE.Close();
FSAppend.Close();
}
}
Your code does seem to close the file properly but not in an exception-safe manner.
You also have some unnecessary code in there (like using (FS = File.Create(dailyLog)) { } FS.Close(); ).
The smallest modification looks like this:
else
{
//if (!File.Exists(dailyLog))
//{
// using (FS = File.Create(dailyLog)) { }
// FS.Close();
//}
using (FileStream FSAppend = new FileStream(dailyLog, FileMode.Append, FileAccess.Write))
using (StreamWriter TXT_WRITE = new StreamWriter(FSAppend))
{
TXT_WRITE.WriteLine(msg);
}
//TXT_WRITE.Close();
//FSAppend.Close();
}
But I would rewrite this whole method like:
private void LogEvent(string filename,bool AppendTxt,string msg)
{
string sLogFormat = DateTime.Now.ToShortDateString().ToString() + " "
+ DateTime.Now.ToLongTimeString().ToString() + " ==> ";
msg = sLogFormat + msg;
// create directory
if (System.IO.Directory.Exists("C:\\Users\\DT-Npax\\Desktop\\LOGS1") != true)
{
Directory.CreateDirectory("C:\\Users\\DT-Npax\\Desktop\\LOGS1");
}
string dailyLog = "C:\\Users\\DT-Npax\\Desktop\\LOGS1" + "\\" + filename + ".log";
if (AppendText)
System.IO.File.AppendAllText(dailylog, msg);
else
System.IO.File.WriteAllText(dailylog, msg);
}
There is no need to pre-create or delete files.
Wrap the streams in a using block since they implement IDisposable.
I must say this code is a little odd...
using (FS = File.Create(dailyLog)) { }
FS.Close();
StreamWriter TXT_WRITE = new StreamWriter(dailyLog);
TXT_WRITE.WriteLine(msg);
TXT_WRITE.Close();
Shouldn't it be something like:
using (FileStream FS = File.Create(dailyLog))
{
using(StreamWriter TXT_WRITE = new StreamWriter(dailyLog))
{
TXT_WRITE.WriteLine(msg);
}
}

Categories

Resources