Say I want to define a TempFileStream class that creates a temporary file using Path.GetTempFileName() method. A temporary file must be deleted when TempFileStream's object is no longer needed, e.g. closed or disposed:
class TempFileStream: FileStream
{
string m_TempFileName = Path.GetTempFileName();
public TempFileStream(FileMode fileMode): base(m_TempFileName,fileMode) {}
/// ...
public ovverride Dispose(bool disposing)
{
/// ???
}
}
How should I implement this simply and safely?
Try this one instead:
The FileOptions.DeleteOnClose option will ensure that the OS deletes the temporary file automatically when you close out the file. No need for a special Dispose method, because it's all taken care of for you.
This is an interesting idea, but there's something about this design that troubles me. Forgive me if you've already addressed this in your design. But if your design is just a simple wrapper around
FileStream
, there's a subtle but, I think, significant problem.If you're deleting the file when the stream is closed, that means that the only way to actually use the data in the file is if the
FileAccess
isReadWrite
. Correct? In other words, you'll be using the file with code that looks like this:The problem I see is that
ReadDataFromTempFile
is expecting the file to be opened for read access, not read/write access. And this opens the door for some bugs that I think will be very hard to find. Consider code like this:...when compared with this:
Sure, the first method is shorter than the second. But the second method will throw an exception if
ProcessOutput
calls a method that writes toTempStream
. (Or sets a property whose set accessor raises an event whose event handler dispatches a call to a method that writes toTempStream
, which how this problem will probably end up happening.) The first one will just produce unexpected results for no apparent reason.You can get around this, I think, by having your
TempFileStream
class open the underlyingFileStream
usingFileAccess.Write
. Then implement aRewind
method that closes thisFileStream
and creates a new one that usesFileAccess.Read
. If you do that, any method that tries to write to the file while it's opened for read access (or vice versa) will at least throw an exception.Basically according to TempFileStream logic you always use just created file with unique name (that is what Path.GetTempFileName does) and you always delete it after its use. So there is no need to provide constructor that accepts FileMode as you always use it in the same mode.
I know this is an older thread, but here's an alternate solution. I started to implement the TempFileStream, but I wanted more concurrency. My use-case involves exporting [potentially MBs of] database results to a CSV file via MVC. I want to begin downloading to the client as soon as data are available from the database query rather than wait for a potentially large temp file to be written before I start downloading.
In this solution, I launch the query in a separate thread which fills an AnonymousPipeStream. The main thread can then slurp the data from the other end of the pipe as its available. It uses .Net 4 Tasks.
Hope someone else finds this useful.
-Rob
Controller method:
Model:
You should add proper exception handling for File.Delete if you need to.