Keeping Things Tidy

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.

Example Code - Open File

Here's the start of a file I've written that opens up an image file for reading, using fopen.

type openImageFile0
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.

fclose(fids(1));

Example Code - Manage Open, Close, and Errors Using try/catch

Now let's look at another version of the code that will close the file it opens before returning.

type openImageFile1
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
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.

Example Code - Use onCleanup to Ensure File Closes

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.

type openImageFile2
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


Example Code - Use onCleanup and Process After Opening the File

Let's see the next version of the file.

type openImageFile3
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.

Example Code - Use onCleanup and Process and Close File on Completion

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.

type openImageFile4
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.

type run4
function y = run4
% run4 processes an image file.
[fid,C] = openImageFile4();
blocksize = 100;
y = [];
while something
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.

Other Uses?

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.

Published with MATLAB® 7.6

|