Known Issues w/ File.AppendText()

J

JerryWEC

I'd like to know if there are any known issues with using AppendText()
method. I'm trying to write data to a log file using it and I'm having some
issues. I keep getting an error message from my ProcessException() handler
saying "The process cannot access the file 'C:\Temp\Logging\LogFileX.log'
because it is being used by another process.

Here is my code I was using. Previously I was using a Using statement for
the StreamWriter (sw)...

Private Sub WriteDataToFile(ByVal FileName As String, ByVal DataString As
String)

Dim sw As StreamWriter = File.AppendText(FileName)

Try

If File.Exists(FileName) Then

'Using sw As StreamWriter = File.AppendText(FileName)

sw.WriteLine(DataString)

'sw.Flush() 'Update text to file.

sw.Close() 'Close StreamWriter and underlying file.

'End Using

Else

Throw New FileNotFoundException

End If

Catch ex As Exception

sw.Close() 'Close StreamWriter and underlying file.

Common.Instance.ProcessException(Common.Instance.CurrentMethodName(),
ex)

End Try

End Sub

I am using File.Exist() Shared method and FileInfo objects to see if the
file exist and to check the file size, etc. Could these cause problems
writing to the file? I am writing a lot of messages to the my .log file
using a loop in a test project. I seem to get this error message while
initially writing a message to the file and when I create a new .log file.
When I write to a new .log file it will skip 5 to 8 lines of text between
files. Basically when my current .log file reaches maxium size it will
create a new file and start writing to it; LogFile1.log, LogFile2.log,
LogFile3.log, etc. I have a more elabrate naming conventation with
data/time data but I simplified it here.

Is there a better way to write to a log file besides this File.AppendText()?
I don't believe I was initially getting this error message. But I was not
trapping for it or looking for it either.

I normally will not be writing to the log file this fast but for testing
purposes I am writing in a loop some test messages and it is fast. I tried
to add some Thread.Sleep() between 2 and 100 milliseconds but that only
seems to work a little in places. I then put a Thread.Sleep between each
time I write to log file and still getting the error message.

Help! JerryM
 
J

Jon Skeet [C# MVP]

JerryWEC said:
I'd like to know if there are any known issues with using AppendText()
method. I'm trying to write data to a log file using it and I'm having some
issues. I keep getting an error message from my ProcessException() handler
saying "The process cannot access the file 'C:\Temp\Logging\LogFileX.log'
because it is being used by another process.

Here is my code I was using. Previously I was using a Using statement for
the StreamWriter (sw)...

And was it working then? Currently you're not closing the file unless
an exception is thrown - which means next time you try to write to the
file, it won't be able to unless the underlying Stream's finalizer
happens to have been called already to release the file handle.
 
J

JerryWEC

Jon, I'm calling sw.Close() within the If statement and In the trap. In
this case I always have a file the If statement was for good measure when I
was using the Using statement (which I thought closed the object explicitly
anyway). I'm using the following code as well...

Private Sub LogMessageToFile(ByVal strErrorMessage As String)

Try

'Step 1 - Set File Path and File Name.

If CurrentLogFilePathAndName = String.Empty Then

CurrentLogFilePathAndName = BuildFileName() 'Build initial file
name.

Thread.Sleep(500)

End If

'Step 2 - If File is at Max Size create another file, otherwise use
it.

If FileIsAtMaxSize(CurrentLogFilePathAndName) Then ''''''''' This
method is using the FileInfo object and File.Exist().

Thread.Sleep(500)

CurrentLogFilePathAndName = BuildFileName() 'Build a new file
name.

Thread.Sleep(500)

End If

'Step 3 - Write Msg to File.

WriteDataToFile(CurrentLogFilePathAndName, strErrorMessage)

'Step 4 - If File is over Max Files the Delete Oldest File.

DeleteOldestFile()

'Step 5 - Refresh File List. *** Moved to PostMessage()!

Catch ex As Exception

'Raise Event in ProcessException!!! Refer to old VB6 code.

Common.Instance.ProcessException(Common.Instance.CurrentMethodName(),
ex)

End Try

End Sub

I added the Thread.Sleep()'s to make sure everything is closed. I don't see
where I am doing anything wrong. I also put in a Thread.Sleep() before my
code in the WriteDataToFile () (Step 3). I have a property called
CurrentLogFilePathAndName which creates the file when assigned a new file
name using...

If Not File.Exists(value) Then

File.Create(value)

End If

I don't see what I'm doing wrong. Any help is greatly apprecaited! JerryM
 
J

Jon Skeet [C# MVP]

JerryWEC said:
Jon, I'm calling sw.Close() within the If statement and In the trap.

Ah, sorry, I didn't notice the first one.
In this case I always have a file the If statement was for good measure when I
was using the Using statement (which I thought closed the object explicitly
anyway).

Yes, the Using statement will close it already. I don't see why you
thought you needed the "If" even when you were using the Using
statement though.
I'm using the following code as well...

I added the Thread.Sleep()'s to make sure everything is closed. I don't see
where I am doing anything wrong. I also put in a Thread.Sleep() before my
code in the WriteDataToFile () (Step 3). I have a property called
CurrentLogFilePathAndName which creates the file when assigned a new file
name using...

If Not File.Exists(value) Then

File.Create(value)

End If

I don't see what I'm doing wrong. Any help is greatly apprecaited! JerryM

That last bit may well be the problem. File.Create returns a
FileStream, which you're not closing. Try closing it, and see if that
gets rid of the problem.

Note that you'll always have a race condition there - if two threads
both notice that the file isn't there, they could both call Create even
though one will "win" and get there first.
 
J

Jeffrey Tan[MSFT]

Hi Jerry,

Thanks for your further information.

First, are you sure that there is no other processes locking your log
files? To ensure this, I recommend you download "Process Explorer" from the
link below:
http://www.microsoft.com/technet/sysinternals/ProcessesAndThreads/ProcessExp
lorer.mspx

In Process Explorer, you may select "Find"->"Find Handle or DLL...(Ctrl+F)"
and input "LogFileX.log" filename for searching. If any process is locking
this log file, there will be an open handle to this file. This is my
favorite way of finding out which process is locking a file.

If Process Explorer reporting that all the open handles to the log file are
in your application, it means it is threads in your appllication that lock
the file. In this scenario, can you tell me do you use multithreads to
access the log files? Thread.Sleep() method will delay the current thread
execution for a period, it is only useful for multithreading scenario. If
there is only a single thread accessing the log file, Thread.Sleep() will
take no effect, because all the methods/properties in this thread execute
synchronously.

As Jon pointed out, do you close the FileSystem returned by File.Create
method? This may place a lock over the log file which makes the file not
accessible to other code/thread.

Additionally, if you see non-closed file handle in your application in
Process Explorer after normal operation, it means there is file handle leak
in your application(you forget to close certain file stream for that file).

Finally, if you still can not find out the root cause, is it possible for
you to create a little sample application to reproduce this problem? This
will be easier for us to troubleshoot this problem.

Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

JerryWEC

Jon, thank you for discovering my problem! It was the FileStream object!
After I closed it all was well.

Jeffrey, I did download the tool you were talking about but I have not had
time to use it yet. I believe it will be a useful tool. I have needed this
type of tool in TS issues in the past.

I have since have modified the code (with Jon's help) and got it working
well. However, I had a conversation with my boss and he wants me to keep the
StreamWriter open while the file has not reached it's max size. (I switched
from a File.Create() to File.CreateText() object to create the file).

I have this working with a private variable and private property to hold my
StreamWriter object. However, I'm having problems closing the last file. I
have implemented the IDisposable interface with a Finalize and two Dispose
methods.

I have a private variable to hold the disposed flag (boolean). I am not
calling the Dispose(True) method directly which is my problem. Where should
I call my Dispose(True) method to close my last file? I will start a new
thread to solve this problem if no one can help me here.

Note: I just called the public .Dispose() method from my test project and it
did do the disposing explicitly. However, I really would like to have this
handle with out my users having to call .Dispose(). How should I close the
last file when I don't know when the user is finished with my Logging
object? The Logging object is the class my test project is using. Help! :)

Thanks in advance!!! JerryM .
 
J

Jon Skeet [C# MVP]

Note: I just called the public .Dispose() method from my test project and it
did do the disposing explicitly. However, I really would like to have this
handle with out my users having to call .Dispose(). How should I close the
last file when I don't know when the user is finished with my Logging
object? The Logging object is the class my test project is using. Help! :)

They should do it explicitly - the "using" statement will help to do it
automatically.

If they don't call Dispose, they'll have to wait for the finalizer to
kick in. However, you don't need to have a finalizer yourself - the
underlying Stream will have a finalizer which will work just as well.
(And indeed, by the time your finalizer is invoked, the Stream's one
may already have been invoked.)
 
J

JerryWEC

Jon, thanks for the info!

Are there any good resources that talk about how these StreamWriter &
FileStream classes work like if you have a sw object and you have not closed
the object does that mean the file is still open? I'm looking for that
level of information.

When you have a class that you created (class library) what is the best way
to close files open using dispose / finalize / finalizer? I have this
working but it just seems a bit to busy for normal explicit destruction of
managed objects. I can see doing it for unmanaged objects. But if you need
to make sure you close an object or deterministly destroy an object ms way
seems over kill?

JerryM
 
J

Jeffrey Tan[MSFT]

Hi Jerry,

Thanks for your feedback.

There are not many dedicated articles talking about StreamWriter and
FileStream. The best way to understand these 2 classes internal is using
Reflector tool to view the source code of these 2 classes. You may free
download the Reflector in the link below(this is the must have tool to view
all .Net BCL assemblies source code):
http://www.aisto.com/roeder/dotnet/

However, there are still one MSDN article and one blog entry talking about
best practice of clearup StreamWriter and FileStream:
"Garbage Collection: Automatic Memory Management in the Microsoft .NET
Framework"
http://msdn.microsoft.com/msdnmag/issues/1100/gci/
"StreamWriter Buffered Data Lost MDA (or a cute finalizer trick) [Brian
Grunkemeyer]"
http://blogs.msdn.com/bclteam/archive/2004/08/13/214405.aspx

Note: in first "Jeffrey Richter"'s MSDN article, "Forcing an Object to
Clean Up" section is dedicated for FileStream and StreamWriter cleanup,
although I recommend you also read all other sections of this article
because they are the best resource for Garbage Collection topic.

After you read these 2 articles, I am sure you will understand it better. I
will provide some more comment below:

1. There is no need for you to implement IDisposable interface, both
StreamWriter and FileStream have implemented IDisposable interface.
For example, you may use Reflector to view StreamWriter.Close method source
code, I listed below:

//Close method normally calls Dispose(disposing) method to do the internal
work.
public override void Close()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

//Flush the data buffer and close the file handle
protected override void Dispose(bool disposing)
{
try
{
if ((this.stream != null) && (disposing || (!this.Closable &&
(this.stream is __ConsoleStream))))
{
this.Flush(true, true);
....
}
}
finally
{
if (this.Closable && (this.stream != null))
{
try
{
if (disposing)
{
this.stream.Close();
}
}
finally
{
....
base.Dispose(disposing);
}
}
}
}

You may also view FileStream's Close, Dispose methods source code.

2. As stated in "Jeffrey Richter"'s article, after you used StreamWriter to
wrap FileStream in constructor(see below), you should only call
StreamWriter.Close method; this method internally will call
FileStream.Close for you.
StreamWriter sw = new StreamWriter(fs);

3. Yes, once you use StreamWriter to wrap one disk file, StreamWriter will
lock this file for only sharing read not write. This means another code
snippet can not use another FileStream/StreamWriter to open this file for
write again. Internally, StreamWriter will always wrap a FileStream for
that file even you do not explicit create a FileStream. You may use
Reflector to view source code to confirm this:

//the pure string path constructor calls another more parameter constructor
public StreamWriter(string path) : this(path, false,
StreamWriter.UTF8NoBOM, 0x400)
{
}

//This constructor is called by other constructors
public StreamWriter(string path, bool append, Encoding encoding, int
bufferSize) : base(null)
{
if ((path == null) || (encoding == null))
{
throw new ArgumentNullException((path == null) ? "path" :
"encoding");
}
if (bufferSize <= 0)
{
throw new ArgumentOutOfRangeException("bufferSize",
Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
}
Stream stream1 = StreamWriter.CreateFile(path, append);
this.Init(stream1, encoding, bufferSize);
}

//Yes, StreamWriter.CreateFile method internally will create a FileStream
for usage
private static Stream CreateFile(string path, bool append)
{
FileMode mode1 = append ? FileMode.Append : FileMode.Create;
return new FileStream(path, mode1, FileAccess.Write, FileShare.Read,
0x1000, FileOptions.SequentialScan);
}
Note: when creating FileStream, .Net will pass FileShare.Read to share read
operation with other code not write operation.

4. Yes, if your boss wanted to keep the StreamWriter open before file has
reached its max size, you may store this StreamWriter in a variable and
always use this StreamWriter reference to append to the log file. Note:
during this period, you can not create another FileStream or StreamWriter
to write to the same log file, because the original StreamWriter locks this
file now.

After the log file reaches its max size, you may call StreamWriter.Close to
close the handle.

If you still have anything unclear, please feel free to feedback. Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

JerryWEC

Wow! Jeffrey thank you so much!

Comment #4 is what I am doing now. My only concern is I would like to
explicitly close the StreamWriter object on the last file.
(StreamWriter.Close()) From your previous post I'd say the file is
automatically being closed?

I will read the references you provided. I really appreciate all the
information you provided me! Typically, I would just open, write and close
the StreamWriter but powers to be would like to keep the file locked until
finished. (Hopefully this will be faster anyway.)

I will check out all your references and that tool this weekend. I have to
go code now. :)

Super responses Jon and Jeffrey!!!

JerryM
 
J

JerryWEC

Jeffrey,

After reading all of the reference material you provided me I believe I do
need to do a Close() / Dispose() method to explicitly close my StreamWriter
object and under lying file (internal FileStream). Basically in my code
below I create a StreamWriter object in side a property when a new file name
is built. The controlling application has control of this creating of files
through my class library called CLA_Logging.

I create the file using a File.CreateText() which returns the StreamWriter
object which is used for all files (See StreamWriter property). I
explicitly close the previous StreamWriter before reusing the variable
again. Here's the issue I see. I need to be able to explicitly close the
last StreamWriter object as the class object is being distoryed (GC) or at
end of lifetime. I have created a Dispose() method that is called in the
calling application. This seems to work fine. I may have to modify it to
make it work if the application programmer does not call Dispose() method.
I'll want to have the GC finalize the object and call my Dispose method.

I added the code below to help understand my line of thinking...

Private Property StreamWriter() As StreamWriter
Get
Try
Return m_StreamWriter
Catch ex As Exception
ProcessException(CurrentMethodName(), ex)
Return Nothing
End Try
End Get
Set(ByVal value As StreamWriter)
Try
If m_StreamWriter IsNot Nothing Then
m_StreamWriter.Close() 'Close last stream writer object
before re-using...
End If
m_StreamWriter = value
Catch ex As Exception
ProcessException(CurrentMethodName(), ex)
End Try
End Set
End Property


Private Property CurrentLogFilePathAndName() As String
Get
Try
Return m_CurrentLogFilePathAndName
Catch ex As Exception
ProcessException(CurrentMethodName(), ex)
Return Nothing
End Try
End Get
Set(ByVal value As String)
Try
If Not File.Exists(value) Then
StreamWriter = File.CreateText(value)
End If
m_CurrentLogFilePathAndName = value
m_formInstance.lblLogFile.Text = m_CurrentLogFilePathAndName
Catch ex As Exception
ProcessException(CurrentMethodName(), ex)
End Try
End Set
End Property


Private Sub WriteDataToFile(ByVal FileName As String, ByVal DataString
As String)
Try
If File.Exists(FileName) Then
StreamWriter.WriteLine(DataString)
StreamWriter.Flush() 'Update text to file.
Else
'If file is not found the create a new one...
CurrentLogFilePathAndName = BuildFileName() 'Build a new
file name.
StreamWriter.WriteLine(DataString)
StreamWriter.Flush() 'Update text to file.
End If
Catch ex As Exception
ProcessException(CurrentMethodName(), ex)
End Try
End Sub

' Implement IDisposable.
' Do not make this method virtual.
' A derived class should not be able to override this method.
Public Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
' This object will be cleaned up by the Dispose method.
' Therefore, you should call GC.SupressFinalize to
' take this object off the finalization queue
' and prevent finalization code for this object
' from executing a second time.
GC.SuppressFinalize(Me)
End Sub

' Dispose(bool disposing) executes in two distinct scenarios.
' If disposing equals true, the method has been called directly
' or indirectly by a user's code. Managed and unmanaged resources can be
disposed.
' If disposing equals false, the method has been called by the runtime
from inside
' the finalizer and you should not reference other objects.
' Only unmanaged resources can be disposed.
Private Overloads Sub Dispose(ByVal disposing As Boolean)
' Check to see if Dispose has already been called.
If Not Me.m_disposed Then '<-- Only Dispose Once!!!
' If disposing equals true, dispose all managed and unmanaged
resources.
If disposing Then
' Dispose managed resources here...
If m_StreamWriter IsNot Nothing Then
m_StreamWriter.Close() 'Close the last open file.
End If
End If

' Call the appropriate methods to clean up unmanaged resources
here...
' If disposing is false, only the following code is executed.
' *** No Unmanaged Code Yet.
End If
m_disposed = True
End Sub

' This finalizer will run only if the Dispose method does not get
called.
' It gives your base class the opportunity to finalize.
' Do not provide finalize methods in types derived from this class.
Protected Overrides Sub Finalize()
' Do not re-create Dispose clean-up code here.
' Calling Dispose(false) is optimal in terms of
' readability and maintainability.
Dispose(False)
MyBase.Finalize()
End Sub

I'm thinking I can change my Finalize() method's call from Dispose(False) to
Dispose(True) to force the m_StreamWriter.Close() if called by GC.

Or,

Modify my Private Dispose() method as follows...

Private Overloads Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If m_StreamWriter IsNot Nothing Then
m_StreamWriter.Close() 'Close the last open file.
End If
End If
End Sub

In this case I can get rid of the disposing and disposed flags all together.

Food for thought. All input is good! JerryM

Note: I added the code here from notepad. I have not been able to add code
directly from VS2005 without having line formating problems. Looks like
extra spacing under each line of text. (Issue with this News Group paste
command?)
 
J

Jeffrey Tan[MSFT]

Hi Jerry,

Thanks for your feedback.

Yes, this is an interesting question: why StreamWriter's Dispose(disposing)
does not flush the internal data buffer if disposing parameter is
false(calls by GC finalizer thread)? This will cause the file stream data
loss if the developer forgets to call Dispose/Close methods explicitly,
which looks a strange design.

Actually, the reason is discussed in the second article I provided you:
http://blogs.msdn.com/bclteam/archive/2004/08/13/214405.aspx

If the FileStream is called by GC finalize first, the underlying file is
closed, then if the StreamWriter is called by GC finalize in a later time,
the dispose method will write to a closed file. The problem arises. The GC
has no knowledge of the order of finalize, so StreamWriter's Dispose(false)
implementation does not flush the buffer for us. So we should always call
Dispose/Close methods explicitly for StreamWriter.

For other class implementation, there is no need to distinguish "disposing"
paramete; we should always release the unmanaged resource in
Dispose(disposing) for both true and false. You may use Reflector to view
Bitmap , Mutex class or other classes without StreamWriter&FileStream
dependency issue, their Dispose(disposing) just release the unmanaged
resource without checking disposing parameter.

So, yes, your Dispose(disposing) method shoud always close the StreamWriter
whatever disposing is true or false. In Finalize() method, you may also
call Dispose(False). This is a more elegant implementation.

If you still have anything unclear, please feel free to tell me, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

JerryWEC

Jeffrey, two questions left...

1] Where can I find Reflector?

2] When I called Dispose(True) from my Finalizer() it threw up this
exception...

[1st Time]
System.ObjectDisposedException was unhandled
Message: Cannot access a closed file.

[2nd Time]
System.ObjectDisposedException was unhandled
Message="Cannot access a closed file."
ObjectName=""
Source="mscorlib"
StackTrace:
at System.IO.__Error.FileNotOpen()
at System.IO.FileStream.Flush()
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean
flushEncoder)
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.StreamWriter.Close()
at CLA_Logging.Logging.Dispose(Boolean disposing)
at CLA_Logging.Logging.Finalize()

Which makes sense to me because the FileStream object did close the file. I
was AutoFlushing the StreamWriter object so all of my data was written to
file.

I just don't like the fact that you can't implicitly dispose of your own
objects in order to close a file that is still open. Does the StreamWriter
object Dispose() of the StreamWriter which calls the internal FileStream
object? I guess I'm still a little unsure how the StreamWriter is working.
Maybe the Reflector will help me understand.

Above [2nd Time] exception is show's FS being Flushed but the file is
already closed. So how did this file get closed if the Dispose() or Close()
was not explicitly called?

??? JerryM
 
J

Jeffrey Tan[MSFT]

Hi Nick,

Thanks for your feedback.

#1, Where can I find Reflector?
I have already provided the link in my second reply, maybe you missed it
:). You may free download the Reflector in the link below(this is the must
have tool to view
all .Net BCL assemblies source code):
http://www.aisto.com/roeder/dotnet/

#2, ObjectDisposedException
Yes, this exception is expected. It seems that you closed FileStream before
StreamWriter. I think you missed my #2 in the second reply. I paste it
below for your reference:
"2. As stated in "Jeffrey Richter"'s article, after you used StreamWriter
to wrap FileStream in constructor(see below), you should only call
StreamWriter.Close method; this method internally will call
FileStream.Close for you."

So, you should not call FileStream.Close/Dispose methods, because
StreamWriter still needs it. You should always call StreamWriter.Close,
which closes FileStream either for you.

Hope this is clear to you now. If anything unclear, please feel free to
tell me, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

JerryWEC

Jeffrey, thanks for the Reflector link I did miss it. [sorry]

On the #2 issue, I am not closing the FileStream myself. I'm not even
closing the StreamWriter object, which is my problem. Because I don't know
when the last time the file is being used (written), I need to close the
last file on destruction of the object. Right now the user's of my DLL will
have to call Dispose(). I may create a .Close() method for them as well. I
was hoping that I could have the Finalizer clean up this last file. The
only reason I'm doing this code this way is my boss is wanting me to keep
the files opened and locked until each one has reached the max size.

I would not have this issue if I open, wrote to file, and then closed the
file.

Note: When I put Dispose(True) inside my finalizer the Dispose method was
trying to close the file (using StreamWriter object), but it was already
cleaned up or GC. I'm going to research how the Reflector works on this
StreamWriter object. Maybe it can shed some light on the subject for me. I
am doing a AutoFlush on each StreamWriter object so the data looks like it
is not getting lost. Does the Reflector show you the code in VB as well as
C#? I'm assuming just C#. I my have to look at this Reflector code a while.

Jeffrey, thanks for all your help!!! I have learn a great deal!

JerryM
 
J

JerryWEC

This Relector tool is very cool! Once you find your methods your looking
at. thanks again!

JerryM
 
J

Jeffrey Tan[MSFT]

Hi Jerry,

Thanks for your further information!

Yes, I see the problem more clear now. Actually, this further problem is
caused by the same reason as the GC finalizer dependency issue.

Your class' Finalizer calls StreamWriter's Dispose(true) to close the
underlying FileStream. However, the FileStream object may cleaned by the GC
first, so FileStream's Finalize method is already called to close the
underlying file. Once the GC calls your class's Finalize method, your
methods calls StreamWriter.Dispose(true), which closes the the FileStream a
second time. Then the ObjectDisposedException is thrown. So your finalize
method should not call StreamWriter.Dispose method to help the developer to
close the StreamWriter/FileStream.

Yes, I see you want to research on StreamWrtier that how does .Net FCL
resolves this Finalize dependency issue for StreamWrtier. Actually, the
answer is already discussed in the article below:
http://blogs.msdn.com/bclteam/archive/2004/08/13/214405.aspx

That is: StreamWrtier does not do anything to resolve this problem.
StreamWrtier will not close the underlying FileStream if you forget to
invoke its Dispose method explicitly. The principle here is that Microsoft
always requires you to invoke Dispose()/Close() method instead of relying
on the Finalizer, or all the buffered data may be lost.

Finally, I am sure you have discovered that Reflector can help you to view
the source code in all the languages, C#, VB.net, IL etc... :)

If you need further help, please feel free to post, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

JerryWEC

Jeffrey, sorry for being such a pest! (Thanks a bunch!)

Normally and in the future all of my StreamWriter objects will be used with
a using statement or at least I will write to the file and then Close() the
StreamWriter object. (My preferred way to do it anyway.)

I am doing the AutoFlush = True for each StreamWriter object and this seems
to flush all of the data to the file anyway. I was doing a manual Flush()
after each WriteLine(). Is there any speed advantage of AutoFlush over
individual Flush() calls?

Happy Holidays and a Merry Christmas to all!

JerryM
 
J

Jeffrey Tan[MSFT]

Hi Jerry,

No, you are a nice customer, I am glad to work with you.

Setting AutoFlush to true has the same effect of calling
StreamWriter.Flush() method after each StreamWriter.Write() operation. If
you use Reflector to examine all the overloading StreamWriter.Write()
methods, you will find the following statement at the end:
if (this.autoFlush)
{
this.Flush(true, false);
}

However, I do not recommend setting AutoFlush=ture, since it will disable
the data buffer of StreamWriter. Delay writing bufferring of StreamWriter
is helpful to improve StreamWriter.Write() method performance, because
multiple StreamWriter.Write() operations can be combined in a single disk
write. Disk I/O is a slow operation comparing to the memory operation, so
fewer I/O writting with data bufferring will yeild better performance.

Merry Christmas to you and have a good new year :)

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

JerryWEC

Jeffrey, the following code does a check to see if autoFlush is equal to
true so that was why I was asking if there is any speed advantage of using
autoFlush. I want to flush the data to the file as soon as I can because
I'm not sure which file or file write will be the last one. Under normal
operations this logging dll will not be writting to the file that much.
Currently I'm writing a lot of messages in a loop every time I click a
button but normally this module will write messages with error's occur and
hopefully that is few and far between.

Reference:

if (this.autoFlush)
{
this.Flush(true, false);
}

Thanks Again! JerryM
 

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