In the past, when you opened a file in a MATLAB program, you had to keep track of it so you could close it under all possible conditions, i.e., if reading or processing failed, worked partially, or worked perfectly. You could achieve this using the catch block after a try. But you still might have to know before closing the file if everything you wanted to do was complete. Code could easily get awkward and buggy if there were lots of code paths to watch out for. With R2008a, you can use the onCleanup class to help you out more cleanly.
Here's the start of a file I've written that opens up an image file for reading, using fopen.
function openImageFile0 % openImageFile Open an image file. fd = fopen('pout.tif');
If I run it, you can see that I never close the file.
openImageFile0() fids = fopen('all') filename = fopen(fids(1)); filename(end-30:end)
fids = 3 ans = toolbox\images\imdemos\pout.tif
Tidy up now.
Now let's look at another version of the code that will close the file it opens before returning.
function openImageFile1 % openImageFile1 Open/process file while ensuring file is % closed on finish. try fd = fopen('pout.tif'); if fid == -1 error('LS:NoImageFile','no such file') end doMoreHere(fd); catch Ex disp('Can not read file') end if fid ~= -1 fclose(fid); end
You can see that, even with try/catch, since I always want to close the image file, I have some extra logic at the end of the file. And I have to be careful to know whether the error occurs because the file was never opened, or if instead the error occurs in later processing.
Here's a file roughly equivalent to the first one, but it ensures that the image file is closed when the function is finished running.
function openImageFile2 % openImageFile2 Open an image file for further processing. % Note: this doesn't do what you want, since the file will % be closed after completing and the file identifier won't % be active for use upon completion. fd = fopen('pout.tif'); C = onCleanup(@()fclose(fd));
To see that this works we first check that no files are open, run the function, and make sure that no files are open afterwards.
fb = fopen('all'); openImageFile2() fp = fopen('all'); noFilesOpen = isequal(fp,fb,)
noFilesOpen = 1
Let's see the next version of the file.
function fd = openImageFile3 % openImageFile3 Open an image file for further processing. % Note: this doesn't do what you want, since the file will % be closed after completing and the file identifier won't % be active for use upon completion. fd = fopen('pout.tif'); C = onCleanup(@()fclose(fd));
This function returns the file identifier, but as we'll see, the file is closed once the function returns. This means that any processing/reading we were planning to do with the file after calling the open function will not work (since the file will no longer be open).
fb = fp; fid = openImageFile3() fp = fopen('all'); noFilesOpen = isequal(fp,fb,)
fid = 3 noFilesOpen = 1
Even though fid is returned from the function call, the file is no longer open. This is because the onCleanup object C is cleared from existence once openImageFile3 completes execution.
Here's the last version of the file for this blog. As long as you call it with 2 outputs, you are good to go.
function [fd, C] = openImageFile4 % openImageFile4 Open an image file for further processing. % Note: this does what you want, provided you call the % function with both output arguments. When you are done % cleaned up and the onCleanup object will trigger the file % closing. % Don't even open file if function isn't called with 2 outputs. if nargout < 2 error('LS:MustHave2Outputs','must call with 2 outputs') end fd = fopen('pout.tif'); C = onCleanup(@()fclose(fd));
This version returns the file identifier and the onCleanup object. Once you have processed your file, simply clear the onCleanup object and the file will close.
To see how this might work, we call it from our function that does the processing.
function y = run4 % run4 processes an image file. [fid,C] = openImageFile4(); blocksize = 100; y = ; while something dat = fread(fid,count); y = doSomething(y,dat); something = update(something); end
You can see that run4 calls openImageFile4, and then does the required processing. Because C will vanish once run4 completes, the file will be closed.
The onCleanup object allows you to more cleanly manage resources such as closing files, closing windows (e.g., last week someone mentioned managing instances of waitbar), managing switching directories. What uses do you foresee for the onCleanup object in your work? Let me know here.