Code covered by the BSD License  

Highlights from
COMPDIRECTORY

image thumbnail
from COMPDIRECTORY by Jiro Doke
GUI tool for comparing the contents of 2 directories

compdirectory(dir1, dir2)
function compdirectory(dir1, dir2)

%COMPDIRECTORY   GUI tool for directory comparison.
%   COMPDIRECTORY opens a GUI for comparing the contents of 2 directories.
%   It performs recursive comparison for all subdirectories. It checks for
%   file/directory names, file sizes, and modification dates.
%
%   In the GUI, if an entry does not exist in one of the directories, then
%   it marks an 'x' in front of it. If an entry has a different file size,
%   then it marks an 's' in front of it. If an entry has the same file size
%   but a different modification date, then it marks a 'd' in front of it.
%
%   COMPDIRECTORY(DIR1, DIR2) starts the GUI with DIR1 and DIR2
%

% Copyright 2006-2011 The MathWorks, Inc.

% Version:
%   v1.0 - original version
%   v1.1 - cosmetic changes to the GUI (December 2, 2006)
%   v1.2 - fixed bug that emerges when a folder name shows up above . or ..
%          (March 30, 2011)
%
% Jiro Doke
% November 2006-2011

versionNum = '1.2';

delete(findall(0, 'tag', 'compdirFig'));

if nargin == 0
  dir1 = '';
  dir2 = '';
end

if ~ischar(dir1) || ~isdir(dir1)
  dir1 = '';
end
if ~ischar(dir2) || ~isdir(dir2)
  dir2 = '';
end

directories.dir1  = dir1;
directories.dir2  = dir2;
str               = '';
fontsize          = 12;
bgcolor           = [.8 .8 .8];

figH = figure(...
  'name'                            , 'Directory Comparison', ...
  'numbertitle'                     , 'off', ...
  'color'                           , bgcolor, ...
  'tag'                             , 'compdirFig', ...
  'units'                           , 'normalized', ...
  'position'                        , [.1 .1 .8 .8], ...
  'resize'                          , 'on', ...
  'resizefcn'                       , @setUIPos, ...
  'keypressfcn'                     , @keypressFcn, ...
  'menubar'                         , 'none', ...
  'toolbar'                         , 'none', ...
  'handlevisibility'                , 'callback', ...
  'visible'                         , 'off', ...
  'defaultuicontrolunits'           , 'pixels', ...
  'defaultuicontrolfontunits'       , 'pixels', ...
  'defaultuicontrolfontsize'        , fontsize, ...
  'defaultuicontrolfontname'        , 'Verdana', ...
  'defaultuicontrolbackgroundcolor' , 'white');

uh(1) = uicontrol(...
  'style'               , 'pushbutton', ...
  'string'              , 'Compare Directories', ...
  'fontweight'          , 'bold', ...
  'enable'              , 'off', ...
  'backgroundcolor'     , bgcolor, ...
  'parent'              , figH, ...
  'callback'            , @compareDirectories);
uh(2) = uicontrol(...
  'style'               , 'popupmenu', ...
  'string'              , [dir1;{'Select a directory...'}], ...
  'value'               , 1, ...
  'tag'                 , 'dir1', ...
  'parent'              , figH, ...
  'callback'            , @selectDirectory);
uh(3) = uicontrol(...
  'style'               , 'popupmenu', ...
  'string'              , [dir2;{'Select a directory...'}], ...
  'value'               , 1, ...
  'tag'                 , 'dir2', ...
  'parent'              , figH, ...
  'callback'            , @selectDirectory);
uh(4) = uicontrol(...
  'style'               , 'listbox', ...
  'max'                 , 3, ...
  'min'                 , 1, ...
  'fontname'            , 'FixedWidth', ...
  'parent'              , figH, ...
  'callback'            , @selectEntryCallback);
uh(5) = uicontrol(...
  'style'               , 'listbox', ...
  'max'                 , 3, ...
  'min'                 , 1, ...
  'fontname'            , 'FixedWidth', ...
  'parent'              , figH, ...
  'callback'            , @selectEntryCallback);
uh(6) = uicontrol(...
  'style'               , 'listbox', ...
  'max'                 , 3, ...
  'min'                 , 1, ...
  'enable'              , 'inactive', ...
  'horizontalalignment' , 'left', ...
  'fontname'            , 'FixedWidth', ...
  'parent'              , figH);
uh(7) = uicontrol(...
  'style'               , 'text', ...
  'fontweight'          , 'bold', ...
  'horizontalalignment' , 'left', ...
  'backgroundcolor'     , bgcolor, ...
  'string'              , 'Comparison Details:', ...
  'parent'              , figH);
st = {'Compare the contents of 2 directories, including subdirectories.', ...
  '', 'Differences are denoted by the following labels:', ...
  'x:  file or directory does not exist', ...
  's:  different file size', ...
  'd:  different modification date'};
uh(8) = uicontrol(...
  'style'               , 'text', ...
  'fontname'            , 'FixedWidth', ...
  'horizontalalignment' , 'left', ...
  'backgroundcolor'     , bgcolor, ...
  'string'              , sprintf('%s\n',st{:}), ...
  'parent'              , figH);

uh(9) = uipanel(...
  'units'               , 'pixels', ...
  'backgroundcolor'     , bgcolor, ...
  'bordertype'          , 'beveledin', ...
  'parent'              , figH);
uh(10) = uicontrol(...
  'style'               , 'text', ...
  'horizontalalignment' , 'center', ...
  'backgroundcolor'     , bgcolor, ...
  'fontweight'          , 'bold', ...
  'string'              , sprintf('Ver %s', versionNum), ...
  'parent'              , uh(9));
uh(11) = uipanel(...
  'units'               , 'pixels', ...
  'backgroundcolor'     , bgcolor, ...
  'bordertype'          , 'beveledin', ...
  'parent'              , figH);
uh(12) = uicontrol(...
  'style'               , 'text', ...
  'horizontalalignment' , 'right', ...
  'backgroundcolor'     , bgcolor, ...
  'fontweight'          , 'bold', ...
  'string'              , '', ...
  'parent'              , uh(11));

setUIPos;

compareDirectories;

set(figH, 'visible', 'on');

%--------------------------------------------------------------------------
% Nested Subfunctions
%--------------------------------------------------------------------------

%--------------------------------------------------------------------------
% setUIPos
%   Set the position of the uicontrols (for resizing)
%--------------------------------------------------------------------------
  function p = setUIPos(varargin)

    set(figH, 'units', 'pixels');
    figPos = get(figH, 'position');
        
    % figure can't be too small or off the screen
    if figPos(3) < 750 || figPos(4) < 500
      figPos(3) = max([750 figPos(3)]);
      figPos(4) = max([500 figPos(4)]);
      screenSize = get(0, 'screensize');
      if figPos(1)+figPos(3) > screenSize(3)
        figPos(1) = screenSize(3) - figPos(3) - 50;
      end
      if figPos(2)+figPos(4) > screenSize(4)
        figPos(2) = screenSize(4) - figPos(4) - 50;
      end
      
      set(figH, 'position', figPos);
      
    end
    
    p = [...
      5, figPos(4)-5-fontsize*2, figPos(3)-10, fontsize*2; ...
      5, figPos(4)-5-fontsize*4, (figPos(3)-15)/2, fontsize*1.5; ...
      (figPos(3)+5)/2, figPos(4)-5-fontsize*4, (figPos(3)-15)/2, fontsize*1.5; ...
      5, fontsize*17.5, (figPos(3)-15)/2, figPos(4)-10-fontsize*21.5; ...
      (figPos(3)+5)/2, fontsize*17.5, (figPos(3)-15)/2, figPos(4)-10-fontsize*21.5; ...
      5, 30, figPos(3)-300, fontsize*13.5; ...
      5, 30+fontsize*13.5, figPos(3)-10, fontsize*1.5; ...
      figPos(3)-290, 30, 285, fontsize*13.5; ...
      2, 1, 100, 25; ...
      2, 2, 96, 20;
      102, 1, figPos(3)-102, 25; ...
      2, 2, figPos(3)-106, 20];
    
    set(uh, 'units', 'pixels');
    set(uh, {'position'}, mat2cell(p, ones(1, size(p, 1)), 4));
    
  end


%--------------------------------------------------------------------------
% keypressFcn
%   Increase or decrease the font size in the GUI
%--------------------------------------------------------------------------
  function keypressFcn(varargin)
    k = get(figH, 'currentkey');
    
    switch k
      case 'equal'
        fontsize = min([fontsize + 2, 24]);
      case 'hyphen'
        fontsize = max([10, fontsize - 2]);
      otherwise
        return;
    end
    
    set(uh(1:end-1), 'fontsize', fontsize);
    setUIPos;
    
  end


%--------------------------------------------------------------------------
% compareDirectories
%   Compare the contents of 2 directories
%--------------------------------------------------------------------------
  function compareDirectories(varargin)

    str = '';

    if ~isempty(directories.dir1) && ~isempty(directories.dir2)
      
      set(uh(12), 'string', 'Comparing ...');drawnow;
      
      [l1, l2, ll1, ll2] = compareDirectoriesEngine(directories.dir1, directories.dir2);

      l1 = cellstr([char(ll1),num2str((1:length(l1))'),repmat(': ', length(l1), 1), char(l1)]);
      l2 = cellstr([char(ll2),num2str((1:length(l2))'),repmat(': ', length(l2), 1), char(l2)]);

      set(uh(4) , 'string', l1 , 'value', 1);
      set(uh(5) , 'string', l2 , 'value', 1);
      set(uh(6) , 'string', str, 'value', 1);
      set(uh(12), 'string', '');
    end

    set(uh(1), 'backgroundcolor', bgcolor, 'enable', 'off');


    %----------------------------------------------------------------------
    % compareDirectoriesEngine
    %   The engine for comparing 2 directories
    %----------------------------------------------------------------------
    function [list1, list2, diff1, diff2] = compareDirectoriesEngine(dirname1, dirname2)

      % LIST1 and LIST2 are list of files/directories in dir1 and dir2,
      % respectively. If an entry does not exist in the directory, an empty
      % string is placed. DIFF1 and DIFF2 are cell arrays that indicate
      % differences. No difference is '  ', missing entry is 'x ', different
      % file size is 's ', and different modification date is 'd '.
      
      d1 = dir(dirname1); d1(ismember({d1.name}, {'.', '..'})) = '';
      d2 = dir(dirname2); d2(ismember({d2.name}, {'.', '..'})) = '';
      
      str = sprintf('%sComparing:|(dir1) %s|(dir2) %s||', ...
        str, dirname1, dirname2);

      % separate into files and directories
      d1dirs  = d1([d1.isdir]);
      d2dirs  = d2([d2.isdir]);
      d1files = d1(~[d1.isdir]);
      d2files = d2(~[d2.isdir]);

      list1 = {};
      list2 = {};
      diff1 = {};
      diff2 = {};

      % traverse through all files in dir1
      for id1 = 1:length(d1files)
        list1 = [list1;{d1files(id1).name}];
        id2 = strcmp(d1files(id1).name, {d2files.name});
        if ~any(id2)
          diff1 = [diff1;{'x  '}];
          diff2 = [diff2;{'x  '}];
          list2 = [list2;{''}];
          str = sprintf('%s    "%s" does not exist in dir2.|', str, d1files(id1).name);
        else
          list2 = [list2;{d2files(id2).name}];
          if d1files(id1).bytes ~= d2files(id2).bytes
            diff1 = [diff1;{' s '}];
            diff2 = [diff2;{' s '}];
            str = sprintf('%s    "%s" has a different file size.|', str, d1files(id1).name);
          elseif ~strcmp(d1files(id1).date, d2files(id2).date)
            diff1 = [diff1;{' d '}];
            diff2 = [diff2;{' d '}];
            str = sprintf('%s    "%s" has a different modification date.|', str, d1files(id1).name);
          else % same file
              diff1 = [diff1;{'   '}];
              diff2 = [diff2;{'   '}];
          end
          % remove from the list
          d2files(id2) = '';
        end
      end

      % traverse through the remainding files in dir2
      % these files do not exist in dir1
      list2 = [list2;{d2files.name}'];
      list1 = [list1;repmat({''},length(d2files),1)];
      diff1 = [diff1;repmat({'x  '},length(d2files),1)];
      diff2 = [diff2;repmat({'x  '},length(d2files),1)];
      for id2 = 1:length(d2files)
        str = sprintf('%s    "%s" does not exist in dir1.|', str, d2files(id2).name);
      end
      str = sprintf('%s|', str);

      % traverse through all directories in dir1
      subDirs = [];
      for id1 = 1:length(d1dirs)
        id2 = strcmp(d1dirs(id1).name, {d2dirs.name});
        if ~any(id2)
          list1 = [list1;{['\', d1dirs(id1).name]}];
          list2 = [list2;{''}];
          diff1 = [diff1;{'x  '}];
          diff2 = [diff2;{'x  '}];
          str = sprintf('%s    directory "%s" does not exist in dir2.|', str, d1dirs(id1).name);
        else
          subDirs = [subDirs; id1, id2];
        end
      end

      % traverse through the remainding directories in dir2
      for id2 = 1:length(d2dirs)
        id1 = strcmp(d2dirs(id2).name, {d1dirs.name});
        if ~any(id1)
          list1 = [list1;{''}];
          list2 = [list2;{['\', d2dirs(id2).name]}];
          diff1 = [diff1;{'x  '}];
          diff2 = [diff2;{'x  '}];
          str = sprintf('%s    directory "%s" does not exist in dir1.|', str, d2dirs(id2).name);
        end
      end

      % recursive comparison of subdirectories
      for ii = 1:size(subDirs, 1)
        list1 = [list1;{['\', d1dirs(subDirs(ii, 1)).name]}];
        list2 = [list2;{['\', d2dirs(subDirs(ii, 2)).name]}];
        if ~strcmp(d1dirs(subDirs(ii, 1)).date, d2dirs(subDirs(ii, 2)).date)
          diff1 = [diff1;{' d '}];
          diff2 = [diff2;{' d '}];
          str = sprintf('%s    directory "%s" has a different modification date.|', str, d1dirs(subDirs(ii, 1)).name);
        else
          diff1 = [diff1;{'   '}];
          diff2 = [diff2;{'   '}];
        end
        str = sprintf('%s|', str);
        [l1, l2, ll1, ll2] = compareDirectoriesEngine(...
          fullfile(dirname1, d1dirs(subDirs(ii, 1)).name), ...
          fullfile(dirname2, d2dirs(subDirs(ii, 2)).name));
        if ~isempty(l1)
          list1 = [list1;cellstr([repmat(' ', length(l1), 2), char(l1)])];
          list2 = [list2;cellstr([repmat(' ', length(l2), 2), char(l2)])];
          diff1 = [diff1;ll1];
          diff2 = [diff2;ll2];
        end
      end
    end
  end


%--------------------------------------------------------------------------
% selectEntryCallback
%   Update selection to show the same entry on both lists
%--------------------------------------------------------------------------
  function selectEntryCallback(varargin)

    val = get(varargin{1}, 'value');
    listtop = get(varargin{1}, 'listboxtop');

    set(uh(4:5), 'value', val, 'listboxtop', listtop);

  end


%--------------------------------------------------------------------------
% selectDirectory
%   Select directory for comparison
%--------------------------------------------------------------------------
  function selectDirectory(varargin)

    dirs = cellstr(get(varargin{1}, 'string'));
    val = get(varargin{1}, 'value');

    tagname = get(varargin{1}, 'tag');

    if strcmp(dirs{val}, 'Select a directory...')  % select new directory
      d = uigetdir(directories.(tagname), 'Select a directory');
      if ischar(d)
        dirs = [dirs(1:end-1);{d};dirs(end)];
        set(varargin{1}, 'string', dirs, 'value', length(dirs)-1);

        directories.(tagname) = d;
        set(uh(4:6), 'string', {}, 'value', 1);
      else % canceled
        if ~isempty(directories.(tagname))
          id = find(strcmp(directories.(tagname), dirs));
        else
          id = length(dirs);
        end
        set(varargin{1}, 'value', id);
        return;
      end
    else % selected existing directory from the list
      directories.(tagname) = dirs{val};
      set(uh(4:6), 'string', {}, 'value', 1);
    end
    
    if ~isempty(directories.dir1) && ~isempty(directories.dir2)
      set(uh(1), 'backgroundcolor', [1 .75 .75], 'enable', 'on');
    else
      set(uh(1), 'backgroundcolor', bgcolor, 'enable', 'off');
    end
    
  end
end




%#ok<*AGROW>

Contact us at files@mathworks.com