List of files from directories/files list or browser

by

 

06 Feb 2012 (Updated )

Returns cell array of file names, needed by various functions.

subFoldersList=folderSubFolders(foldersList, nFolderDepth, flagGUI, browserTitle, isSortABC)
function subFoldersList=folderSubFolders(foldersList, nFolderDepth, flagGUI, browserTitle, isSortABC)
%% folderSubFolders
% Returns cell array of folder names located under input list (cell array) of folders.
%  
%% Syntax:
%     subFoldersList=folderSubFolders;
%     subFoldersList=folderSubFolders(foldersList);
%     subFoldersList=folderSubFolders(foldersList, nFolderDepth);
%     subFoldersList=folderSubFolders(foldersList, nFolderDepth, flagGUI);
%     subFoldersList=folderSubFolders(foldersList, nFolderDepth, flagGUI, browserTitle);
%     subFoldersList=folderSubFolders(foldersList, nFolderDepth, flagGUI, browserTitle, isSortABC);
%  
%% Description:
% This functions goal is to return a list (cell array) of names of sub-folders located 
%   under user defined folders list. The input should be a a cell array of parent
%   directories names. The function also supports input of a single directory name string.
%   Alternatively, the user can choose the folders using the OS explorer- by enabling the
%   'flagGUI' input.
%   Function properties:
%       - It is not recursive but iterative.
%       - It does not change the current folder (not using "cd" command).
%       - It uses "ls" function, which is supposed to be faster than "dir" function.
%       - According to some measurements I've made it runs faster than the alternatives. 
%       - I also believe it is clearly written and documented, so it should be easy to
%           understand and maintain.
%  
%% Input arguments (defaults exist):
%	foldersList-    a path to the parent directory. A string with a single folder name, or
%       a cell array of folder names.
%   nFolderDepth-   an integer specifying how deep should the function go over the sub
%       folders tree. This way "0" would return user inputs (echo), while "Inf", or
%       any value higher then number of folder tree levels would go over all existing sub
%       folders.
%   flagGUI-        When enabled allows the user to choose the folders using the folder
%                   browser (explorer in case of Windows OS).
%   browserTitle-   a string presented in the folder browser menu.
%   isSortABC-     	a logical flag allowing sorting the folders alphabetically when 
%                   enabled. When disabled, folders will be ordered by their "folder
%                   floor".
%  
%% Output arguments:
%     subFoldersList-    a cell array of found file names, with absolute path.
%
%% Issues & Comments:
%   None.
%
%% Example I- simply present found file names:
%	foldersList=folderSubFolders(pwd, 1);
%   fprintf('Folder names (+path) under current directory\n');
%   fprintf('%s\n', foldersList{:});
%
%	foldersList=folderSubFolders(pwd, Inf);
%   fprintf('All sub folders ( full path) in current directory.\n');
%   fprintf('%s\n', foldersList{:});
%
%% Example II- find oversized files:
% maxFileSize=10; %[Mb]
% fileNamesList=folderFiles([], Inf);
% filesData=cellfun(@dir, fileNamesList, 'UniformOutput', false);
% isEmptyCell=cellfun(@isempty, filesData, 'UniformOutput', false);
% isEmptyCellArr=cat(2, isEmptyCell{:});
% filesData=filesData(~isEmptyCellArr);
% fileNamesList=fileNamesList(~isEmptyCellArr);
% filesDataStructArr=cat(2, filesData{:});
% filesSizeMB=cat(2, filesDataStructArr.bytes)/1024/1024;
% 
% isFileOversized=(filesSizeMB > maxFileSize);
% fprintf('Oversized files:\n');
% iOverSizedFiles=find(isFileOversized);
% for iFile=iOverSizedFiles
%     fprintf( 'Size- %.1f [MB]\t%s\n', filesSizeMB(iFile),...
%         fileNamesList{iFile} );
% end
%
%% See also:
%   - filesFullName
%   - levelFolderName
%   - ls
%   - dir 
%
%% Revision history:
% First version: Nikolay S. 2013-03-10.
% Last update:   Nikolay S. 2013-04-10.
%
% *List of Changes:*
% 2013-04-28- replaced for by while loop to take care of nFolderDepth=Inf
% 2013-04-10- folderFullPath is used instead of the same code inside this function

%% Default params values
if nargin < 4
    isSortABC=[];
end

if nargin < 3
    if nargin==0 % if no iputs supplied- force using explorer
        foldersList={};
    end
    if isempty(foldersList)
        flagGUI=true;
    else
        flagGUI=false; % by default, explorer will not be used
    end
end

if nargin < 2 % if nFolderDepth is not specified, search one folder level
    nFolderDepth=1;
end

% when user did nor specify flag value, but specified further parameters- enable browser
if isempty(foldersList) && isempty(flagGUI)
    % if user has explicitly set flagGUI=false,  it will remain false,
    % (good for preventing unwanted user promts)
    flagGUI=true;
end

if exist('browserTitle', 'var')~=1
    browserTitle='Select input files';
end

if exist('isSortABC', 'var')~=1 || isempty(isSortABC)
    isSortABC=false;
end

if exist('flagGUI', 'var')~=1 || isempty(flagGUI)
    flagGUI=false;
end

if (flagGUI)
    %% Select the directories/files using the Explorer
    if nargin < 2
        nFolderDepthUserChoise = questdlg('Please choose folders depth:', browserTitle,...
            '0-Current folder files', 'Custom value', 'Inf-All sub-folders files',...
            'Inf-All sub-folders files');
        switch(nFolderDepthUserChoise)
            case('0-Current folder files')
                nFolderDepth=0;
            case('Custom value')
                inputdlgPrompt='Enter folders depth value';
                inputdlgTitle='Custom folders depth';
                inputStr=inputdlg( inputdlgPrompt, inputdlgTitle, 1, {'1'} );
                nFolderDepth=round( str2double(inputStr) );
            otherwise
                nFolderDepth=Inf;
        end     % switch(nFolderDepthUserChoise)
    end     % if nargin < 2
    
    prevChosenFolder=pwd;
    anotherDir='More';
    while ~strcmpi(anotherDir, 'Finish')
        explStartDir = uigetdir(prevChosenFolder, browserTitle);
        
        if ~isequal(explStartDir, 0) % If cancel was not pressed
            % store last opened directory, to start with it on next Explorer use.
            prevChosenFolder=explStartDir; 
            foldersList=cat( 1, foldersList, {explStartDir} );
        end
               
        anotherDir = questdlg({'Need to choose another folder?',...
            'Press ''More'', to choose another folder.',...
            'Press ''Finish'' to finish choosing folders.'},...
            'Input folders selection',...
            'More', 'Finish', 'Finish');
    end     % while ~strcmpi(anotherDir,'Finish')
end     % if (flagGUI)

if ischar(foldersList) % convert string to cell aray
    foldersList={foldersList};
end

%% prepare foldersList elements folders for further processing
% get foldersList elements full folders path instead of relative/partial path if one was
% used
foldersList=cellfun(@folderFullPath, foldersList, 'UniformOutput', false);


%% Search for sub-folders
subFoldersList=foldersList;
prevFoldersAgregator=foldersList;
iFolderLevel=1;
while iFolderLevel <= nFolderDepth  % Scan folders nFolderDepth 
    nCurrFolders=length(prevFoldersAgregator); % number of sub-folders in current level
    currFoldersAgregator={};
    for iSubFolder=1:nCurrFolders % go through current sub folders
        % find their subfolders
        currFolders=getFolderSubFolders( prevFoldersAgregator{iSubFolder} ); 
        if ~isempty(currFolders)
            if ~isequal( size(subFoldersList, 1), numel(subFoldersList) )
                subFoldersList=reshape(subFoldersList, [], 1);
            end
            if ~isequal( size(currFolders, 1), numel(currFolders) )
                currFolders=reshape(currFolders, [], 1);
            end

            subFoldersList=cat( 1, subFoldersList, currFolders );
            currFoldersAgregator=cat( 1, currFoldersAgregator, currFolders );
        end     % if ~isempty(currFolders)
    end     % for iFolder=1:nCurrFolders
    
    if isempty(currFoldersAgregator) % isequal(prevFoldersAgregator, currFoldersAgregator)
        break;
    end
    
    % update list of relevant folders for current iFolderLevel
    prevFoldersAgregator=currFoldersAgregator; 
    iFolderLevel=iFolderLevel+1;
end     % for iFolderLevel=0:(nFolderDepth-1)  % Scan folders nFolderDepth 

if isSortABC
   subFoldersList=sort( subFoldersList ); 
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%                       Servise sub function                               %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function folderSubFolders=getFolderSubFolders( currFolder )
%% Find current folder sub folders
namesList=cellstr( ls(currFolder) );
folderSubFolders=strcat( currFolder, filesep, namesList );

% Remove non-folder elements- this can be ommited, but it will increase run time...
isFolderName=cellfun(@isdir, folderSubFolders);
folderSubFolders=folderSubFolders(isFolderName);

% Get each folder names elements: path, name extention.
[~, folderName, folderExt]=cellfun(@fileparts, folderSubFolders, 'UniformOutput', false);

% Folder must have a non empty name, and an empty extention
isFolder=not(cellfun( @isempty, folderName)) & cellfun( @isempty, folderExt);
% Remove names that are not legal folder names
folderSubFolders=folderSubFolders(isFolder);

Contact us