getFullPath - Get absolute canonical path of a file or folder Absolute path names are safer than relative paths, when e.g. a GUI or TIMER callback changes the current directory. Only canonical paths without "." and ".." can be recognized uniquely. Long path names (>259 characters) require a magic initial key "\\?\" to be handled by Windows API functions, e.g. for Matlab's FOPEN, DIR and EXIST. FullName = getFullPath(Name, Style) INPUT: Name: String or cell string, absolute or relative name of a file or folder. The path need not exist. Unicode strings, UNC paths and long names are supported. Style: Style of the output as string, optional, default: 'auto'. 'auto': Add '\\?\' or '\\?\UNC\' for long names on demand. 'lean': Magic string is not added. 'fat': Magic string is added for short names also. The Style is ignored when not running under Windows. OUTPUT: FullName: Absolute canonical path name as string or cell string. For empty strings the current directory is replied. '\\?\' or '\\?\UNC' is added on demand. NOTE: The M- and the MEX-version create the same results, the faster MEX function works under Windows only. Some functions of the Windows-API still do not support long file names. E.g. the Recycler and the Windows Explorer fail even with the magic '\\?\' prefix. Some functions of Matlab accept 260 characters (value of MAX_PATH), some at 259 already. Don't blame me. The 'fat' style is useful e.g. when Matlab's DIR command is called for a folder with les than 260 characters, but together with the file name this limit is exceeded. Then "dir(getFullPath([folder, '\*.*], 'fat'))" helps. EXAMPLES: cd(tempdir); % Assumed as 'C:\Temp' here getFullPath('File.Ext') % 'C:\Temp\File.Ext' getFullPath('..\File.Ext') % 'C:\File.Ext' getFullPath('..\..\File.Ext') % 'C:\File.Ext' getFullPath('.\File.Ext') % 'C:\Temp\File.Ext' getFullPath('*.txt') % 'C:\Temp\*.txt' getFullPath('..') % 'C:\' getFullPath('..\..\..') % 'C:\' getFullPath('Folder\') % 'C:\Temp\Folder\' getFullPath('D:\A\..\B') % 'D:\B' getFullPath('\\Server\Folder\Sub\..\File.ext') % '\\Server\Folder\File.ext' getFullPath({'..', 'new'}) % {'C:\', 'C:\Temp\new'} getFullPath('.', 'fat') % '\\?\C:\Temp\File.Ext' COMPILE: Automatic: InstallMex getFullPath.c uTest_getFullPath Manual: mex -O getFullPath.c Download: http://www.n-simon.de/mex Run the unit-test uTest_getFullPath after compiling. Tested: Matlab 6.5, 7.7, 7.8, 7.13, WinXP/32, Win7/64 Compiler: LCC2.4/3.8, BCC5.5, OWC1.8, MSVC2008/2010 Assumed Compatibility: higher Matlab versions Author: Jan Simon, Heidelberg, (C) 2009-2013 matlab.THISYEAR(a)nMINUSsimon.de See also: CD, FULLFILE, FILEPARTS.
0001 function File = getFullPath(File, Style) 0002 % getFullPath - Get absolute canonical path of a file or folder 0003 % Absolute path names are safer than relative paths, when e.g. a GUI or TIMER 0004 % callback changes the current directory. Only canonical paths without "." and 0005 % ".." can be recognized uniquely. 0006 % Long path names (>259 characters) require a magic initial key "\\?\" to be 0007 % handled by Windows API functions, e.g. for Matlab's FOPEN, DIR and EXIST. 0008 % 0009 % FullName = getFullPath(Name, Style) 0010 % INPUT: 0011 % Name: String or cell string, absolute or relative name of a file or 0012 % folder. The path need not exist. Unicode strings, UNC paths and long 0013 % names are supported. 0014 % Style: Style of the output as string, optional, default: 'auto'. 0015 % 'auto': Add '\\?\' or '\\?\UNC\' for long names on demand. 0016 % 'lean': Magic string is not added. 0017 % 'fat': Magic string is added for short names also. 0018 % The Style is ignored when not running under Windows. 0019 % 0020 % OUTPUT: 0021 % FullName: Absolute canonical path name as string or cell string. 0022 % For empty strings the current directory is replied. 0023 % '\\?\' or '\\?\UNC' is added on demand. 0024 % 0025 % NOTE: The M- and the MEX-version create the same results, the faster MEX 0026 % function works under Windows only. 0027 % Some functions of the Windows-API still do not support long file names. 0028 % E.g. the Recycler and the Windows Explorer fail even with the magic '\\?\' 0029 % prefix. Some functions of Matlab accept 260 characters (value of MAX_PATH), 0030 % some at 259 already. Don't blame me. 0031 % The 'fat' style is useful e.g. when Matlab's DIR command is called for a 0032 % folder with les than 260 characters, but together with the file name this 0033 % limit is exceeded. Then "dir(getFullPath([folder, '\*.*], 'fat'))" helps. 0034 % 0035 % EXAMPLES: 0036 % cd(tempdir); % Assumed as 'C:\Temp' here 0037 % getFullPath('File.Ext') % 'C:\Temp\File.Ext' 0038 % getFullPath('..\File.Ext') % 'C:\File.Ext' 0039 % getFullPath('..\..\File.Ext') % 'C:\File.Ext' 0040 % getFullPath('.\File.Ext') % 'C:\Temp\File.Ext' 0041 % getFullPath('*.txt') % 'C:\Temp\*.txt' 0042 % getFullPath('..') % 'C:\' 0043 % getFullPath('..\..\..') % 'C:\' 0044 % getFullPath('Folder\') % 'C:\Temp\Folder\' 0045 % getFullPath('D:\A\..\B') % 'D:\B' 0046 % getFullPath('\\Server\Folder\Sub\..\File.ext') 0047 % % '\\Server\Folder\File.ext' 0048 % getFullPath({'..', 'new'}) % {'C:\', 'C:\Temp\new'} 0049 % getFullPath('.', 'fat') % '\\?\C:\Temp\File.Ext' 0050 % 0051 % COMPILE: 0052 % Automatic: InstallMex getFullPath.c uTest_getFullPath 0053 % Manual: mex -O getFullPath.c 0054 % Download: http://www.n-simon.de/mex 0055 % Run the unit-test uTest_getFullPath after compiling. 0056 % 0057 % Tested: Matlab 6.5, 7.7, 7.8, 7.13, WinXP/32, Win7/64 0058 % Compiler: LCC2.4/3.8, BCC5.5, OWC1.8, MSVC2008/2010 0059 % Assumed Compatibility: higher Matlab versions 0060 % Author: Jan Simon, Heidelberg, (C) 2009-2013 matlab.THISYEAR(a)nMINUSsimon.de 0061 % 0062 % See also: CD, FULLFILE, FILEPARTS. 0063 0064 % $JRev: R-G V:032 Sum:7Xd/JS0+yfax Date:15-Jan-2013 01:06:12 $ 0065 % $License: BSD (use/copy/change/redistribute on own risk, mention the author) $ 0066 % $UnitTest: uTest_getFullPath $ 0067 % $File: Tools\GLFile\getFullPath.m $ 0068 % History: 0069 % 001: 20-Apr-2010 22:28, Successor of Rel2AbsPath. 0070 % 010: 27-Jul-2008 21:59, Consider leading separator in M-version also. 0071 % 011: 24-Jan-2011 12:11, Cell strings, '~File' under linux. 0072 % Check of input types in the M-version. 0073 % 015: 31-Mar-2011 10:48, BUGFIX: Accept [] as input as in the Mex version. 0074 % Thanks to Jiro Doke, who found this bug by running the test function for 0075 % the M-version. 0076 % 020: 18-Oct-2011 00:57, BUGFIX: Linux version created bad results. 0077 % Thanks to Daniel. 0078 % 024: 10-Dec-2011 14:00, Care for long names under Windows in M-version. 0079 % Improved the unittest function for Linux. Thanks to Paul Sexton. 0080 % 025: 09-Aug-2012 14:00, In MEX: Paths starting with "\\" can be non-UNC. 0081 % The former version treated "\\?\C:\<longpath>\file" as UNC path and 0082 % replied "\\?\UNC\?\C:\<longpath>\file". 0083 % 032: 12-Jan-2013 21:16, 'auto', 'lean' and 'fat' style. 0084 0085 % Initialize: ================================================================== 0086 % Do the work: ================================================================= 0087 0088 % ############################################# 0089 % ### USE THE MUCH FASTER MEX ON WINDOWS!!! ### 0090 % ############################################# 0091 0092 % Difference between M- and Mex-version: 0093 % - Mex does not work under MacOS/Unix. 0094 % - Mex calls Windows API function getFullPath. 0095 % - Mex is much faster. 0096 0097 % Magix prefix for long Windows names: 0098 if nargin < 2 0099 Style = 'auto'; 0100 end 0101 0102 % Handle cell strings: 0103 % NOTE: It is faster to create a function @cell\getFullPath.m under Linux, but 0104 % under Windows this would shadow the fast C-Mex. 0105 if isa(File, 'cell') 0106 for iC = 1:numel(File) 0107 File{iC} = getFullPath(File{iC}, Style); 0108 end 0109 return; 0110 end 0111 0112 % Check this once only: 0113 isWIN = strncmpi(computer, 'PC', 2); 0114 MAX_PATH = 260; 0115 0116 % Warn once per session (disable this under Linux/MacOS): 0117 persistent hasDataRead 0118 if isempty(hasDataRead) 0119 % Test this once only - there is no relation to the existence of DATAREAD! 0120 %if isWIN 0121 % Show a warning, if the slower Matlab version is used - commented, because 0122 % this is not a problem and it might be even useful when the MEX-folder is 0123 % not inlcuded in the path yet. 0124 % warning('JSimon:getFullPath:NoMex', ... 0125 % ['getFullPath: Using slow Matlab-version instead of fast Mex.', ... 0126 % char(10), 'Compile: InstallMex getFullPath.c']); 0127 %end 0128 0129 % DATAREAD is deprecated in 2011b, but still available. In Matlab 6.5, REGEXP 0130 % does not know the 'split' command, therefore DATAREAD is preferred: 0131 hasDataRead = ~isempty(which('dataread')); 0132 end 0133 0134 if isempty(File) % Accept empty matrix as input: 0135 if ischar(File) || isnumeric(File) 0136 File = cd; 0137 return; 0138 else 0139 error(['JSimon:', mfilename, ':BadTypeInput1'], ... 0140 ['*** ', mfilename, ': Input must be a string or cell string']); 0141 end 0142 end 0143 0144 if ischar(File) == 0 % Non-empty inputs must be strings 0145 error(['JSimon:', mfilename, ':BadTypeInput1'], ... 0146 ['*** ', mfilename, ': Input must be a string or cell string']); 0147 end 0148 0149 if isWIN % Windows: -------------------------------------------------------- 0150 FSep = '\'; 0151 File = strrep(File, '/', FSep); 0152 0153 % Remove the magic key on demand, it is appended finally again: 0154 if strncmp(File, '\\?\', 4) 0155 if strncmpi(File, '\\?\UNC\', 8) 0156 File = ['\', File(7:length(File))]; % Two leading backslashes! 0157 else 0158 File = File(5:length(File)); 0159 end 0160 end 0161 0162 isUNC = strncmp(File, '\\', 2); 0163 FileLen = length(File); 0164 if isUNC == 0 % File is not a UNC path 0165 % Leading file separator means relative to current drive or base folder: 0166 ThePath = cd; 0167 if File(1) == FSep 0168 if strncmp(ThePath, '\\', 2) % Current directory is a UNC path 0169 sepInd = strfind(ThePath, '\'); 0170 ThePath = ThePath(1:sepInd(4)); 0171 else 0172 ThePath = ThePath(1:3); % Drive letter only 0173 end 0174 end 0175 0176 if FileLen < 2 || File(2) ~= ':' % Does not start with drive letter 0177 if ThePath(length(ThePath)) ~= FSep 0178 if File(1) ~= FSep 0179 File = [ThePath, FSep, File]; 0180 else % File starts with separator: 0181 File = [ThePath, File]; 0182 end 0183 else % Current path ends with separator: 0184 if File(1) ~= FSep 0185 File = [ThePath, File]; 0186 else % File starts with separator: 0187 ThePath(length(ThePath)) = []; 0188 File = [ThePath, File]; 0189 end 0190 end 0191 0192 elseif FileLen == 2 && File(2) == ':' % "C:" current directory on C! 0193 % "C:" is the current directory on the C-disk, even if the current 0194 % directory is on another disk! This was ignored in Matlab 6.5, but 0195 % modern versions considers this strange behaviour. 0196 if strncmpi(ThePath, File, 2) 0197 File = ThePath; 0198 else 0199 try 0200 File = cd(cd(File)); 0201 catch % No MException to support Matlab6.5... 0202 if exist(File, 'dir') % No idea what could cause an error then! 0203 rethrow(lasterror); 0204 else % Reply "K:\" for not existing disk: 0205 File = [File, FSep]; 0206 end 0207 end 0208 end 0209 end 0210 end 0211 0212 else % Linux, MacOS: --------------------------------------------------- 0213 FSep = '/'; 0214 File = strrep(File, '\', FSep); 0215 0216 if strcmp(File, '~') || strncmp(File, '~/', 2) % Home directory: 0217 HomeDir = getenv('HOME'); 0218 if ~isempty(HomeDir) 0219 File(1) = []; 0220 File = [HomeDir, File]; 0221 end 0222 0223 elseif strncmpi(File, FSep, 1) == 0 0224 % Append relative path to current folder: 0225 ThePath = cd; 0226 if ThePath(length(ThePath)) == FSep 0227 File = [ThePath, File]; 0228 else 0229 File = [ThePath, FSep, File]; 0230 end 0231 end 0232 end 0233 0234 % Care for "\." and "\.." - no efficient algorithm, but the fast Mex is 0235 % recommended at all! 0236 if ~isempty(strfind(File, [FSep, '.'])) 0237 if isWIN 0238 if strncmp(File, '\\', 2) % UNC path 0239 index = strfind(File, '\'); 0240 if length(index) < 4 % UNC path without separator after the folder: 0241 return; 0242 end 0243 Drive = File(1:index(4)); 0244 File(1:index(4)) = []; 0245 else 0246 Drive = File(1:3); 0247 File(1:3) = []; 0248 end 0249 else % Unix, MacOS: 0250 isUNC = false; 0251 Drive = FSep; 0252 File(1) = []; 0253 end 0254 0255 hasTrailFSep = (File(length(File)) == FSep); 0256 if hasTrailFSep 0257 File(length(File)) = []; 0258 end 0259 0260 if hasDataRead 0261 if isWIN % Need "\\" as separator: 0262 C = dataread('string', File, '%s', 'delimiter', '\\'); %#ok<REMFF1> 0263 else 0264 C = dataread('string', File, '%s', 'delimiter', FSep); %#ok<REMFF1> 0265 end 0266 else % Use the slower REGEXP, when DATAREAD is not available anymore: 0267 C = regexp(File, FSep, 'split'); 0268 end 0269 0270 % Remove '\.\' directly without side effects: 0271 C(strcmp(C, '.')) = []; 0272 0273 % Remove '\..' with the parent recursively: 0274 R = 1:length(C); 0275 for dd = reshape(find(strcmp(C, '..')), 1, []) 0276 index = find(R == dd); 0277 R(index) = []; 0278 if index > 1 0279 R(index - 1) = []; 0280 end 0281 end 0282 0283 if isempty(R) 0284 File = Drive; 0285 if isUNC && ~hasTrailFSep 0286 File(length(File)) = []; 0287 end 0288 0289 elseif isWIN 0290 % If you have CStr2String, use the faster: 0291 % File = CStr2String(C(R), FSep, hasTrailFSep); 0292 File = sprintf('%s\\', C{R}); 0293 if hasTrailFSep 0294 File = [Drive, File]; 0295 else 0296 File = [Drive, File(1:length(File) - 1)]; 0297 end 0298 0299 else % Unix: 0300 File = [Drive, sprintf('%s/', C{R})]; 0301 if ~hasTrailFSep 0302 File(length(File)) = []; 0303 end 0304 end 0305 end 0306 0307 % "Very" long names under Windows: 0308 if isWIN 0309 if ~ischar(Style) 0310 error(['JSimon:', mfilename, ':BadTypeInput2'], ... 0311 ['*** ', mfilename, ': Input must be a string or cell string']); 0312 end 0313 0314 if (strncmpi(Style, 'a', 1) && length(File) >= MAX_PATH) || ... 0315 strncmpi(Style, 'f', 1) 0316 % Do not use [isUNC] here, because this concerns the input, which can 0317 % '.\File', while the current directory is an UNC path. 0318 if strncmp(File, '\\', 2) % UNC path 0319 File = ['\\?\UNC', File(2:end)]; 0320 else 0321 File = ['\\?\', File]; 0322 end 0323 end 0324 end 0325 0326 % return;