While FILEPATH, FILE_DIRNAME, and FILE_BASENAME are quite useful, the rules they follow don’t match the way I think about filenames. There are several small issues that together make them painful for me to use. In this article, I will present my problems with these routines and I’ll show the routine I use to deal with filenames.

For example, the default root directory for FILEPATH is the IDL installation directory:

IDL> print, filepath('a.dat')
/Applications/itt/idl71/a.dat

Even if you explicitly set ROOT_DIR to the empty string, it will still use the installation directory:

IDL> print, filepath('a.dat', root_dir='')
/Applications/itt/idl71/a.dat

To get a relative path, you need to use

IDL> print, filepath('a.dat', root='.')
./a.dat

Another issue with FILEPATH is that the SUBDIRECTORY keyword is ignored if TMP is set:

IDL> print, filepath('a.dat', subdir=['b', 'c'], /tmp)
/var/folders/oi/oixrR4s-HaKpnx2R73UM+k+++TI/-Tmp-/a.dat

Since I use relative paths and temporary files a lot, these are annoying issues for me.

The routines for decomposing a filename into its constituent parts also have issues, even though they are consistent with the UNIX dirname and basename utilities. The UNIX utilities are written the way they are so that a filename can be decomposed by successive calls to dirname, but I would prefer to decompose all in one step. When given a directory name to begin with, FILE_DIRNAME fails to return the directory name provided:

IDL> print, file_dirname('a/')
.

On the other hand, FILE_BASENAME returns a directory name (not a basename) when given a directory name:

IDL> print, file_basename('a/')
a

While this might follow the rules set forth in the documentation, this does not abide by common sense i.e for a/, the directory name is a/ and the basename is the empty string.

The routine I have been using is MG_FILENAME which uses the MGffFilename class. For example, a filename can be defined as follows:

IDL> f = mg_filename('a.dat', subdir=['b', 'c'])
IDL> print, f
b/c/a.dat

Then decomposed like so:

IDL> f = mg_filename(f, basename=basename, extension=ext, $
IDL> dirname=dirname, directories=dirs)
IDL> print, f
b/c/a.dat
IDL> print, basename
a.dat
IDL> print, ext
dat
IDL> print, dirname
b/c/
IDL> print, dirs
b c

It is also more flexible with temporary files:

IDL> print, mg_filename('test.dat', subdir=['cavity'], /tmp)
/var/folders/lW/lWHkX5xME4eiMboghT4mpk+++TM/-Tmp-/cavity/test.dat

This hasn’t received a lot of use on Windows, but I use it regularly on Mac/Unix.