问题
I have a singleton-like class that can do some logging output:
class Foo
{
private static Foo instance;
private System.IO.StreamWriter os;
private Foo()
{
this.os = System.IO.File.CreateText( "D:/tmp/test" );
}
public static Foo Instance
{
get
{
if ( instance == null )
instance = new Foo();
return instance;
}
}
public void Log( string s )
{
os.Write( s );
}
}
When I use that in a sample program like
class Program
{
private static void Main( string[] args )
{
Foo.Instance.Log( "asdf\n" );
}
}
the file is being created, but no output is written. I assume this is because the StreamWriter
has never been flushed.
I tried to repair the class by calling to Close()
in ~Foo()
:
~Foo()
{
os.Close();
}
but this yields a ObjectDisposedException
. Apparently Foo.os
has already been disposed when Foo
's destructor is called.
How do I ensure that my StreamWriter
is flushed "at last"?
EDIT
Setting this.os.AutoFlush = true;
works. Adding a Flush()
method to Foo
and calling it in appropiate places does as well, but I'm interested if there any way of doing without.
回答1:
You can use StreamWriter which does have a Flush method.
There is another option for what you are trying to accomplish, you can use File.AppendAllText and will work. This way the StreamWriter is not open all the time.
class Foo
{
private static Foo instance;
private System.IO.StreamWriter os;
private Foo()
{
this.os = new System.IO.StreamWriter("D:/tmp/test.txt");
}
public static Foo Instance
{
get
{
if (instance == null)
instance = new Foo();
return instance;
}
}
public void Log(string s)
{
os.WriteLine(s);
os.Flush();
}
public void Log2(string s)
{
System.IO.File.AppendAllText(@"D:/tmp/test2.txt",s);
}
}
回答2:
First of all, using a singleton creates problems in its own right, and this did not need another proof. Here, it's cleanup for a disguised global. The StreamWriter
does not auto-flush on program end and according to the documentation,
You must call Close to ensure that all data is correctly written out to the underlying stream.
Thanks to an answer to "Self-closing StreamWriter singleton" from @PeterDuniho a possible solution could be changing the constructor to
private Foo()
{
this.os = System.IO.File.CreateText( "D:/tmp/test" );
System.AppDomain.CurrentDomain.ProcessExit +=
(sender, eventArgs) => this.os.Close();
}
Considering the problem of calling Close()
in the destructor, I should not have ignored the "finalizers are not of much use anyway" written all over the place. In this case, as garbage collection does not use a specific order, the StreamWriter
object has already been collected and cannot be closed in its resurrected zombie state.
来源:https://stackoverflow.com/questions/36500967/flush-streamwriter-at-the-end-of-its-lifetime