Temporary File Stream

Photo by Dil Assi on Unsplash

One of the tools I use for generating temporary files is a class I wrote about eight years ago called TempFileStream. The class combines several useful aspects of working with temporary files, including: (1) code to generate a safe temporary file name, (2) code to open that file, returning a Stream object, and (3) code to manage the lifetime of that Stream object and remove the underlying temporary file when the Stream is closed. The result of creating an instance of TempFileStream is no different than any other Stream object, so it’s very easy to use in your own code.

The trimmed down code for the class is shown here:

 

This looks like more code than it actually is. Most of what’s here simply wraps a base stream object and then defers to that object for the various properties and methods that are inherited by the Stream base class.

Let’s start by looking at the two constructors. The first constructor accepts no arguments and is used to generate a randomly named file in the temp directory. Notice that we don’t use the Path.GetTempFileName method to generate the actual file name. That’s because that method simply wraps an underlying call to the Win32 SDK GetTempFileName method, which contains a built-in limitation of 65,535 unique file names before it rolls over and start reusing file names again.

That’s something Windows developers have been working around since the 80’s and we’re still at it here in 2018.

 

Way to fix your bugs, Microsoft …

 

Anyway, since we’re generating a pseudo-random file name using the Path.GetTempFileName method we need to deal with the possibility that there might be an occasional name collision. That’s what the while loop in the first constructor does. It checks for the existence of the randomly named file, and if it exists, it generates another file name instead and then checks that file name for a collision as well.

Name collisions are probably (hopefully) rare, but they might still happen on a busy production server. So after we’ve dealt with the possibility of a name collision, we simply create the underlying disk file and saves the stream in the BaseStream property, which we inherited as part of the base class.

The second constructor accepts a file name as an argument so it doesn’t perform the check for a naming collision, since it assumes that the file name passed to is is unique. It simply creates the underlying disk file and, again, saves the stream in the BaseStream property.

The first constructor is good for general use since it takes care of finding a suitable temporary file name. The second constructor is good for when you need to specify a file name yourself and you’re willing to assume the risk of naming collisions.

Once a TempFileStream object has been created, using either constructor, the object simply acts like any other Stream object. The CanRead, CanSeek, CanWrite, Length, Position, Flush, Read, Seek, SetLength, Write methods all defer to the inner Stream object we created in the constructor, in the BaseStream object.

The Dispose method should be looked at though, since here is where we remove the underlying disk file when the TempFileStream object is disposed of. That’s an important point since that behavior isn’t standard for any other kind of Stream object. When you cleanup a TempFileStream object, the underlying disk file goes away, so, don’t store anything in a TempFileStream object that you might want later on, after the dispose method has been called. A TempFileStream object is for short term, temporary, disk storage.

 

Using a TempFileStream object is no different than any other Stream object, with the exception that it removes it’s associated disk file during cleanup. Here is a quick example of how to use the class:

 

That’s about it for the class. TempFileStream is a good tool for anything you might have traditionally used a temporary file for. Just remember not to use it for long-term disk storage.

 

Have fun with the code!

 

The code for this article is part of my NUGET package CG.IO, which can be downloaded for free at https://github.com/CodeGator/CG.IO

The source code for the CG.IO project lives on Github and can be obtained for free at https://www.nuget.org/packages/CG.IO