tags:

views:

237

answers:

7

Hi peeps

I'm writing a little application whereby I want to write the results of the operations to a file.

Basically what I want to do is open a stream to a file (I'm thinking FileStream, but am open to suggestions), write data to the file, then close it at a later date.

So I've got a class called ReportFile, with methods:

.Create( string path )

.WriteInfo( string a, string b, string c ) ; //Or something like this...

//Then sometime in the future

.Close()

So the class using the ReportFile class will create an instance, call WriteInfo(..) multiple times until it is finished doing whatever it needs to do, then call Close() at some point in the future.

Now I know I need to implement a Dispose pattern on the ReportFile class to ensure that if anything goes screwey that the handle to the file gets appropriately dealt with.

However I haven't been able to find anything thus far on the interweb showing a good way of keeping the file open and then checking to see if it needs to be closed, most of the examples just open the file do the writing, then close it - all within a using{} construct.

In the ReportFile class I want to be able to check if the FileStream instance is not closed so that I can close it and free up resource.

Anyone know of a good link to reference or any other advice ?

(Ohh I should mention that I don't do C# full time, it's only a hobby thing, so if this is a dumb question, my apologies ;-)

+3  A: 

The ReportFile would just have a TextWriter instance variable - which you would dispose within your own Dispose() method.

Why do you want to have an explicit Close() method, btw? Your callers should be using a using statement anyway, so why would they want to explicitly call Close as well?

Jon Skeet
The various stream classes in the `System.IO` namespace follow that pattern (implementing the `IDisposable.Dispose` method explicitly and exposing only the `Close` method)
Adam Robinson
@Adam: That's true, but I suspect that's more historical than anything else. If there's a `Close` method, people may call it explicitly and forget to use a `using` statement - IMO they're more likely to do the right thing if they *have* to use `Dispose`.
Jon Skeet
I agree with Jon, if you are maintaining an IDisposable resource through the class instance the class should implement IDisposable. I just wish there was better support for the compiler to flag IDisposable implementations when not in a using or something. You know there are people that don't read the documentation to know the class supports IDisposable or just forget completely about it and handle it accordingly.
ewrankin
But a `using` block isn't always feasible, namely if the lifetime of the object needs to extend beyond the scope of a single method. I can't say that exposing `Dispose` *isn't better* than an explicit implementation and exposing `Close` instead, but I also don't think it's necessarily a bad thing if--like the `Stream` classes--the exposed function is behaviorally synonymous with calling `Dispose` (if you look at the code for `Dispose`, all it does is call `Close`).
Adam Robinson
@ewrankin: But we aren't talking about whether or not to implement `IDisposable`, we're talking about whether or not to use an *explicit implementation* of `IDisposable` and expose a different method to do the cleanup. Historically files and handles and streams of most kinds are "opened" and "closed", so I think it makes sense (in this particular case, and others) to follow this approach.
Adam Robinson
@Adam: This brings out a inherent problem with IDisposable and resource management is either way there is a problem with an explicit call that may never get called.
ewrankin
@Adam: Note that there's no "Open" method here, so that convention is already gone. I just think that exposing "Close" may be encouraging bad habits - and that in itself *is* a bad thing, IMO.
Jon Skeet
+3  A: 

Is there a particular reason that you have to keep the file open?

In this situation I would simply open the file each time using FileMode.Append (or pass append=true to StreamWriter ctor) and then close it again afterwards with a using. eg:

void WriteInfo(string text)
{
    // Second parameter to StreamWriter ctor is append = true
    using(StreamWriter sw = new StreamWriter(logFilePath, true))
    {
         sw.WriteLine(text);
    }
}

Taking this approach you can don't really need a Create() or Close() method. The append=true will create the file if it does not exist.

Ash
Or just use File.AppendText in that case...
Jon Skeet
Hi Ash,thanks for replying.Yeah I considered that as well. However, the little app I'm creating is a Search/Replace tool that will log all the changes to a file to prove what it has done -)
JustAPleb
@JustAPleb, I see where you are coming from however the Open/Close should not be the bottleneck. Writing to the file is going to be the slower, even more so when the file grows in size. Do some performance testing and if you actually find it is an issue, buffering your writes to memory and batching file access is going to give the biggest performance boost. BTW, can't you use log4net or some other proven logging library?
Ash
Hi AshLog4Net - I had thought about that actually, but never used it before.I'll look into it.Thanks for your help.
JustAPleb
I can recommend Log4Net, it had a few quirks but it did the job when I last used it a few years ago.
Ash
A: 

I would suggest using the "using" construct and keep the file open only whilst saving.

An idea might be to build the content in memory then save it when you're ready. using a StringBuilder for example.

Mark Redman
A: 

Here is a good link look for the open function.

Hogan
A: 

In the case you simply won't use a using {} construct, you can use the IDisposable interface: http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx

Webleeuw
+1  A: 

Justa, i think that you're overthinking this feature a bit. The reason that you're seeing examples with the using construct is that using{} with file write is quite fast and safe.

Chances are that you're not opening and closing the file several times a second so there's no need to keep it open all the time and thus risking leaving the app without closing the file (which is a PITA to fix after the fact.) Using the using construct makes certain that the resource, your file in this case, is released and closed properly.

Another piece of advice for programming: don't worry about efficiency at the outset. Get it working first the simplest way you can and improve speed/performance later only if it's necessary.

Paul Sasik
Hi PsasikThe tool im writing is a search and replace app that'll search through all the files in a folder and sub folders and make multiple replaces based on the crtieria given.So after each file that it has performed a search on, it logs the changes it's made to the Report. So if there are a lot of files, then it could be opening/closing the file a lot.
JustAPleb
+1  A: 

public void Create(string path) { mStream = new FileStream(path); }

public void Dispose() { if (mStream != null) mStream.Dispose(); }

adrianm