Module Prelude.File

Additional functions on files and filenames.

File Names

val sep : string

sep is Filename.dir_sep.

val join : string -> string -> string

(join dir name) is like (Filename.concat dir name) except that if name is absolute, it is returned as is.

val components : ?sep:string -> string -> string list

(components ?sep path) is the list of the leading directory components (and possible final file component) of path, as separated by sep (default: Filename.dir_sep).

Invariant: (not (Filename.is_relative p)) && (hd (components p) = sep)

Example: (components "/etc/passwd" = ["/"; "etc"; "passwd"])

val coalesce : ?sep:string -> string list -> string

(coalesce ?sep list) is the filename corresponding to the directory components (and possible final file component) of path separated by sep (default: Filename.dir_sep).

Any list returned by components is guaranteed to be valid input to coalesce, but other lists may raise Invalid_arg:

  • none of the components may be ""
  • none of the component strings in the tl may contain sep, except:
  • sep, exactly, may be the hd

Example: (coalesce ["/"; "etc"; "passwd"] = "/etc/passwd")

val absolutify : string -> string
val squiggle : ?home:(unit -> string) -> string -> string

(squiggle ?home fn) expands the traditional Unix leading "~/" in filename fn to the home directory of the user running the program.

The home function is called to get the user's home directory. The default is Unix.home (which uses Unix.getpwuid); another candidate might be:

default (Unix.home ()) Sys.getenv "HOME" 

to use the value of the environment variable, if defined, but fall back to the passwd database if not.

val temp_file_name : ?temp_dir:string -> string -> string -> string

temp_file_name ?temp_dir prefix suffix returns a filename suitable for an INSECURE temporary file.

This function may be useful for creating temp files that are not the ordinary files that Filename.temp_file and Filename.open_temp_file make, such as fifos, unix domain sockets, or even just directories.

Remember that securely creating (and possibly opening) such a temp file is more complex then merely doing:

  • mkfifo (temp_file_name "foo" "") 0o400

This code was extracted from the source code of OCaml's Filename module.

Predicates

val exists : string -> bool

(exists fn) is true iff the file fn exists.

val readable : string -> bool

(readable fn) is true iff the file fn is readable.

val writeable : string -> bool

(writeable fn) is true iff the file fn is writeable.

val executable : string -> bool

(executable fn) is true iff the file fn is executable.

Types of Files

module Is : sig ... end

Predicates testing the type of a file.

Stat and Lstat

module Stat : sig ... end

Convenient functions to access the fields of the Unix stat structure.

module Lstat : sig ... end

Convenient functions to access the fields of the Unix stat structure of symbolic links.

val follow : ?max:int -> string -> string

(follow ?(max=1000) path) returns an absolute pathname equivalent to path unless:

1. path doesn't exist, in which case Unix.Unix_error (Prelude.Unix.ENOENT, "lstat", _) is raised; or

2. path is a symbolic link, in which case the link is chased, recursively, until a non-symlink is found, in which case an absolute pathname of the final destination is returned; or

3. path is a symbolic link with more than max (default: 1000) levels of redirections, in which case Failure _ is raised.

Commands i.e. Executables

module Command : sig ... end

Functions to find executable programs, possibly in $PATH.

Directories

val withcd : (string -> 'a) -> string -> 'a

(withcd f dir) evaluates (f dir) with the working directory set to dir, guaranteeing to restore the current working directory even in the event of an exception.

Contrived example:

let f () = Sys.file_exists "tmp" in
let a = f () in
let b = File.withcd (fun _ -> f ()) "/" in
[a; b; f ()] = [false; true; false] 
val with_tempdir : ?perm:Unix.file_perm -> ?temp_dir:string -> string -> string -> (string -> 'a) -> 'a

(with_tempdir ?temp_dir prefix suffix f) evaluates (f dir) with the working directory set to dir, guaranteeing to restore the current working directory even in the event of an exception.

dir is a newly created temporary directory, with permissions given by perm, as named by temp_file_name ?temp_file_name prefix suffix. After evaluation of f dir, this directory AND ALL THE FILES IN IT will be removed by rm -rf even in the event of an exception.

val glob : (string -> bool) -> string -> string list

(glob pred dir) is the list of files in dir for which pred returns true.

The predicate is invoked with a filename joined onto dir; e.g. if (glob pred ".") then pred will called like (pred "./foo").

The filenames returned will also be joined on dir.

See Extended.Re.fileglob for one suitable predicate.

val folddir : (string -> 'a -> 'a) -> 'a -> string -> ('a, string) Stdlib.result

(folddir f init dir) folds the function f across all of the filenames the directory dir, with init the initial accumulator.

The filenames passed to f are all relative to dir.

N.B.: the list of files never contains "." nor "..".

Error msg is returned if there is an error opening dir as a directory,

type seqitem = exn option * int * string

The type of items returned by to_seq.

The components of the tuple are:

  • None unless an exception occurred
  • the depth: 0 for the starting directory dir itself (only), incremented as we descend
  • the complete pathname relative to the starting dir; if dir is absolute, so will be all the pathnames.
val to_seq : ?follow:bool -> ?xdev:bool -> string -> (exn option * int * string) Seq.t

(to_seq ?follow ?xdev dir) is a sequence consisting of one seqitem for each file in dir and all its subdirectories, recursively.

If follow (default: false) then symlinks to directories will be followed.

If xdev (default: false) then we don't descend into directories on other filesystems.

N.B. neither "." nor ".." are ever returned for any subdir of dir. But dir is returned, so if (dir = ".") then one "." will be returned.

to_seq is about 10% slower than fold, but to_seq is 1. easier to use, and 2. much faster if you are going to quit early.

type 'a folder = exn option -> int -> string -> 'a -> 'a

the type of function parameters for fold.

val fold : ?follow:bool -> ?xdev:bool -> 'a folder -> 'a -> string -> 'a

(fold ?(follow=false) ?(xdev=false) f init dir) folds f over all files in dir, recursively, with init as initial accumulator.

N.B. neither "." nor ".." are ever returned for any subdir of dir. But dir is returned, so if (dir = ".") then one "." will be returned.

f is of the form (f exnopt depth path acc).

exnopt is (Some exn) iff an exception occurred during the directory traversal. The main possibilities are permission denied in reading the directory, and broken symlinks if (follow = true).

depth is 0 for the starting directory dir itself (only), and is incremented as we descend. So all the files and directories directly contained in dir have depth 1, and so on.

path is the complete pathname relative to the starting dir; if dir is absolute, so will be all the pathnames.

acc is the accumulator.

fold is about 10% faster than to_seq but always processes all the files in dir (you can't quit early without resorting to Exn.label and Exn.return).

See Fold for helpful combinators. The following examples don't use any of them.

Example: collect all filenames into a list (ignoring errors):

  • (fold (fun _ _ p a -> cons p a) [] ".") = (fold (fun _ _ -> cons) [] ".")

Example: print exceptions while traversing:

  • (fold (fun eo _ -> Option.maybe (Exn.to_string >> prerr_endline) eo; cons) [] ".")

Example: terminate traversal on any exception:

  • (fold (fun eo _ -> Option.maybe raise eo; cons) [] ".")

Example: count the files under ".", ignoring exceptions:

  • (fold (fun _ _ _ -> succ) 0 ".")
module Fold : sig ... end

Utility Functions and Combinators for fold.

module Deprecated : sig ... end