Finding Files in Directories

The basic directory scanning routine is

file_member_of_directory(?Directory, ?FileName, ?FullName) is true when

  1. Directory is an atom naming a directory;
  2. FileName is an atom conforming to the rules for file names without directory components;
  3. Directory contains an entry with name FileName, and the current process is allowed to know this fact; and
  4. FullName is an atom naming the file, combining both the Directory and the FileName, and FullName names a regular file.

Directory can be an absolute filename or a relative one. FullName will be absolute if Directory is absolute, relative if Directory is relative.

We return the FileName component because that is the component on which pattern matching is generally done. We return the FullName component in order to remove from the user the burden of manipulating the (system-dependent) rules for putting together a directory name and a file name.

This predicate acts as much like a logical relation as it can. Here are some of the ways of using it:

          | ?- file_member_of_directory(foo, Name, Full),
               write(Name=Full), nl, fail.
            %  to enumerate members of the directory
          
          | ?- file_member_of_directory(baz, 'ugh.pl', Full).
            %  to test whether a file 'ugh.pl' is visible in
            %  directory 'baz', and if so return the full name
          
          | ?- file_member_of_directory(Dir, Nam, 'baz/jar.log').
            % if there is a visible regular file baz/jar.log,
            % to return its directory in Dir and name in Nam.
          

file_member_of_directory/3 has two variants:


file_member_of_directory(?FileName, ?FullName)
is the same as file_member_of_directory/3, except that it checks the current directory. You could obtain this effect quite easily by calling file_member_of_directory/3 with first argument ., but in other operating systems the current directory is denoted differently. This provides an operating-system-independent way of searching the current directory. There is one other difference, which is of great practical importance: . is a relative directory name, but file_member_of_directory/2 uses the absolute name for the current directory, so that the FullName you get back will also be absolute. See the description of absolute_file_name/2 in the reference pages. Note the difference between calling
          absolute_file_name(FileName, FullName)
          

and calling

          file_member_of_directory(FileName, FullName)
          

The former will accept any filename, but the FileName must be instantiated. The latter will only accept simple file names with no directory component, and insists that the file must already exist, but in return will generate FileName.

file_member_of_directory(?Directory, ?Pattern, ?FileName, ?FullName)
is the same as file_member_of_directory/3, except that it filters out all the FileNames that do not match Pattern. Pattern is an atom that may contain ? and * wildcards. ? matches any character and * matches any sequence of characters (cf. UNIX csh(1) and sh(1)). The main use for this routine is to select files with a particular extension. Thus,
          | ?- file_member_of_directory(foo,'*.pl',Short,Full).
          

matches files foo/*.pl.

To summarize, the three routines discussed so far are

     file_member_of_directory([Directory, [Pattern, ]]Short, Full)
     

They enumerate FileName-FullName pairs one at a time: in alphabetic order, as it happens.

There is another set of three predicates finding exactly the same solutions, but returning them as a set of FileName-FullName pairs. We follow here the general convention that predicates that return one "thing" have thing in their name, and predicates that return the set of "things" have things in their name.


file_members_of_directory([?Directory, [?Pattern, ]]?Set)
unifies Set with a list of FileName-FullName pairs that name visible files in the given Directory matching the given Pattern. Thus, instead of
          | ?- file_member_of_directory(foo, '*.pl', S, F).
          
          S = 'bat.pl',
          F = 'foo/bat.pl' ;
          
          S = 'fly.pl',
          F = 'foo/fly.pl' ;
          
          no
          

one would find

          | ?- file_members_of_directory(foo, '*.pl', Set).
          
          Set = ['bat.pl'-'foo/bat.pl', 'fly.pl'-'foo/fly.pl']