0
votes

I wrote a function to load mat-files with wildcards in them into a struct, by using dir to catch the wildcards and then invoking load. This is the function:

function S = loadw(varargin)
%LOADW Load variables from file into workspace, with wildcard (*) in file name

filename = varargin{1};

if(ismember('*', filename))
    [pathstr, ~, ext] = fileparts(filename);
    if(isempty(pathstr))
        pathstr = '.';
    end
    if(~strcmp(ext, '.mat'))
        filename = [filename '.mat'];
    end
    dirFiles = dir(filename);
    if(isempty(dirFiles))
        error(['Unable to read file ''' filename ''': no such file or directory.']);
    elseif(numel(dirFiles) == 1)
        varargin{1} = [pathstr filesep dirFiles(1).name];
        S = load(varargin{:});
    else
        S = cell(numel(dirFiles), 1);
        for iFile = 1:numel(dirFiles)
            varargin{1} = [pathstr filesep dirFiles(iFile).name];
            S{iFile} = load(varargin{:});
        end
    end
else
    S = load(varargin{:});
end

This works well, however it can only load a file into a struct, and not into the caller workspace as load does. How can I modify this function to set the variables in the caller workspace?

I thought about using assignin to do this but this means I first load the variables into the function workspace and then transfer them to the caller workspace. I would prefer a method that does not require declaring the variables twice. Is this possible without re-implementing load? Or, perhaps, is there no overhead in declaring the variables twice, so that using assignin('caller',...) would actually be an efficient solution?

2

2 Answers

1
votes

When you do the line

S = load(varargin{:});

It will load the variables in the file as struct elements of S, or S{iFile} as appropriate. If you don't want this, if you just want the variables to go directly into the workspace, you can skip the assignment to S

load(varargin{:});

I generally prefer to avoid loading variables directly into the workspace as you can never be sure what variables are in a file and what it could do to your workspace.

So as an alternative approach, if this is a concern, once you've loaded the variables into S you could then write another block that goes through the struct, pulls out the field names (using the fieldnames function) and then reassigns the S.(fieldname) member to fieldname directly, after having checked it doesn't already exist in the workspace (using exist(fieldname, 1)).

You'd do the assignment itself using eval. Note that Mathworks recently introduced dynamic field referencing for structs and they recommend this over eval in a lot of cases but I think this use case (assigning to a variables named for the field name) still calls for eval.

0
votes

I am convinced that the only options are either to load the files inside the function and then use assignin('caller',...), or to use evalin('caller', 'load(...);'). Between these I choose the latter, as I think avoiding declaring the variables twice merits suffering the drawbacks of an eval function. This is my function now:

function S = loadw(varargin)
%LOADW Load variables from file into workspace, with wildcard (*) in file name

filename = varargin{1};

if(ismember('*', filename))
    [pathstr, ~, ext] = fileparts(filename);
    if(isempty(pathstr))
        pathstr = '.';
    end
    if(~strcmp(ext, '.mat'))
        filename = [filename '.mat'];
    end
    dirFiles = dir(filename);
    if(isempty(dirFiles))
        error(['Unable to read file ''' filename ''': no such file or directory.']);
    elseif(numel(dirFiles) == 1)
        varargin{1} = [pathstr filesep dirFiles(1).name];
        if(nargout > 0)
            S = load(varargin{:});
        else
            strLoadCommand = ['load(''' strjoin(varargin, ''', ''') ''');'];
            evalin('caller', strLoadCommand);
        end
    else
        if(nargout > 0)
            S = cell(numel(dirFiles), 1);
        end
        for iFile = 1:numel(dirFiles)
            varargin{1} = [pathstr filesep dirFiles(iFile).name];
            if(nargout > 0)
                S{iFile} = load(varargin{:});
            else
                strLoadCommand = ['load(''' strjoin(varargin, ''', ''') ''');'];
                evalin('caller', strLoadCommand);
            end
        end
    end
else
    if(nargout > 0)
        S = load(varargin{:});
    else
        strLoadCommand = ['load(''' strjoin(varargin, ''', ''') ''');'];
        evalin('caller', strLoadCommand);
    end
end