How to close a StreamWriter class when the program exits

A

Andrew Falanga

Hi,

I've implemented a logging class for my program that uses the
Singleton pattern (discussed here: http://msdn.microsoft.com/en-us/library/ms998558.aspx).
Now, my log file uses a StreamWriter class object for the file. I'd
like to know how I can reliably call the StreamWriter.Close() function
to make this flush all it's buffers, etc., before exiting the program.

Originally, everything was working but when the program exited, my
files were 0 bytes in length. I wrote a smaller program trying to use
the StreamWriter class (I'm not well versed in C# at all), and I was
using it in the exact same way and everything worked. So, I then
turned my attention to looking at member functions like Flush or Close
and found them in the class definition.

First, I tried making a ctor in my class that called the Close() when
the object was destroyed, but I got an unhandled exception and went to
the debugger. Turns out that Garbage Collection had already destroyed
my object and the dtor was trying to destroy something that didn't
exist. So now I have the Flush() function called in every one of my
class member functions that write new data to the file. This works,
i.e. my data is written to the file, but how could I make this happen
only once in a destructor or something similar?

Andy
 
I

Ignacio Machin ( .NET/ C# MVP )

Hi,

I've implemented a logging class for my program that uses the
Singleton pattern (discussed here:http://msdn.microsoft.com/en-us/library/ms998558.aspx).
Now, my log file uses a StreamWriter class object for the file.  I'd
like to know how I can reliably call the StreamWriter.Close() function
to make this flush all it's buffers, etc., before exiting the program.

Originally, everything was working but when the program exited, my
files were 0 bytes in length.  I wrote a smaller program trying to use
the StreamWriter class (I'm not well versed in C# at all), and I was
using it in the exact same way and everything worked.  So, I then
turned my attention to looking at member functions like Flush or Close
and found them in the class definition.

First, I tried making a ctor in my class that called the Close() when
the object was destroyed, but I got an unhandled exception and went to
the debugger.  Turns out that Garbage Collection had already destroyed
my object and the dtor was trying to destroy something that didn't
exist.  So now I have the Flush() function called in every one of my
class member functions that write new data to the file.  This works,
i.e. my data is written to the file, but how could I make this happen
only once in a destructor or something similar?

Andy

Open & Close the file each time you write a log
 
A

Arne Vajhøj

Andrew said:
I've implemented a logging class for my program that uses the
Singleton pattern (discussed here: http://msdn.microsoft.com/en-us/library/ms998558.aspx).
Now, my log file uses a StreamWriter class object for the file. I'd
like to know how I can reliably call the StreamWriter.Close() function
to make this flush all it's buffers, etc., before exiting the program.

Originally, everything was working but when the program exited, my
files were 0 bytes in length. I wrote a smaller program trying to use
the StreamWriter class (I'm not well versed in C# at all), and I was
using it in the exact same way and everything worked. So, I then
turned my attention to looking at member functions like Flush or Close
and found them in the class definition.

First, I tried making a ctor in my class that called the Close() when
the object was destroyed, but I got an unhandled exception and went to
the debugger. Turns out that Garbage Collection had already destroyed
my object and the dtor was trying to destroy something that didn't
exist. So now I have the Flush() function called in every one of my
class member functions that write new data to the file. This works,
i.e. my data is written to the file, but how could I make this happen
only once in a destructor or something similar?

Other have the exact same problem.

From the docs of log4net TextWriterAppender:

<quote>
ImmediateFlush Property

....

The default behavior is to flush at the end of each append operation.

If this option is set to false, then the underlying stream can defer
persisting the logging event to a later time.

Remarks

Avoiding the flush operation at the end of each append results in a
performance gain of 10 to 20 percent. However, there is safety trade-off
involved in skipping flushing. Indeed, when flushing is skipped, then it
is likely that the last few log events will not be recorded on disk when
the application exits. This is a high price to pay even for a 20%
performance gain.
</quote>

That is also your choices.

Arne
 
M

Manu

Hi,

I've implemented a logging class for my program that uses the
Singleton pattern (discussed here:http://msdn.microsoft.com/en-us/library/ms998558.aspx).
Now, my log file uses a StreamWriter class object for the file.  I'd
like to know how I can reliably call the StreamWriter.Close() function
to make this flush all it's buffers, etc., before exiting the program.

Originally, everything was working but when the program exited, my
files were 0 bytes in length.  I wrote a smaller program trying to use
the StreamWriter class (I'm not well versed in C# at all), and I was
using it in the exact same way and everything worked.  So, I then
turned my attention to looking at member functions like Flush or Close
and found them in the class definition.

First, I tried making a ctor in my class that called the Close() when
the object was destroyed, but I got an unhandled exception and went to
the debugger.  Turns out that Garbage Collection had already destroyed
my object and the dtor was trying to destroy something that didn't
exist.  So now I have the Flush() function called in every one of my
class member functions that write new data to the file.  This works,
i.e. my data is written to the file, but how could I make this happen
only once in a destructor or something similar?

Andy

Why dont you try and implement the IDisposable interface in your
logging class.
And in the Dispose Method Add the call to StreamWrtire.Close().

This design would be consistent with .net Framework.
 
A

Andrew Falanga

For log files in particular, I recommend not using StreamWriter.  Use a
direct stream as you can open the file to allow other programs (read
"Notepad") to open the file for review while the program is still running..
As for the flush, if you are using the StreamWriter, you can set the
autoflush property to true.  Also, the Stream class has the same problem
with the program closing.

Mike.

Is this the same as the FileStream object I recall finding? I started
off by using that but nearly every example I found on-line for opening
file objects in C# showed the opening of a FileStream object and then ?
wrapping? that object in a StreamWriter object. (I hope I have that
correct.) After finding an example of using just the StreamWriter
object to write to a file, I thought that this would eliminate a
"middle-man."

So, you're recommending using just a FileStream object?

Andy
 
A

Andrew Falanga

Not really.  If you provide StreamWriter with a filename instead of an  
actual FileStream instance, it basically winds up creating the FileStream 
anyway.  StreamWriter does, after all, write to _Streams_, and your  
filename string isn't a Stream.

The main reason for providing a FileStream to StreamWriter is so that you 
can control how the file for the FileStream is opened, buffered, etc.  For  
example, you can provide flags to the FileStream constructor that allows  
for shared read access to the file while it's still open.

But if you don't need that level of control, there's not really any good  
reason to create the FileStream instance explicitly, rather than letting  
StreamWriter create it.


If you are writing text to the file, you should use StreamWriter.  
Otherwise, you wind up just reinventing the wheel.

Note that while you do want to flush after each write, you probably will  
want to do this simply by setting the AutoFlush property to "true".  As 
the documentation describes, if you call Flush() explicitly, that will  
also flush any state in the encoder being used by the StreamWriter, which 
could cause problems with the output (personally, I think the odds of  
something going wrong are low, but better safe than sorry).

Pete

Thanks for the response. Primarily, I think that text will be written
to the file. However, there may be cases where, in the execution of
the program writing bytes, or binary, to the file may be necessary.
For this reason, as I was reading things over this morning, I decided
to re-code using FileStream instead of StreamWriter. All was working
well, until I came to this function in my class:

public void Write(byte[] ba)
{
.....
}

This is fine if someone passes me a byte array, but I need to handle
the case of a single byte. How would I cast this to a byte array?
Would it be simpler to make an overloaded function that takes a single
byte and, internal to the function, makes a byte array assigns that
single byte value to the new array and then calls the Write() function
that takes the byte array? That seems awefully complicated for a
single byte. Are there still better methods of addressing this in C#
that what I'm attempting to do?

Andy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top