boost/filesystem/operations.hpp

Introduction
Header synopsis
Class directory_iterator
    Constructors
    Other_functions
Operations functions
    exists
    symbolic_link_exists
    is_directory
    is_empty
    equivalent
    file_size
    last_write_time
    create_directory
    remove
    remove_all
    rename
    copy_file
    initial_path
    complete
    system_complete

Introduction

The boost/filesystem/operations.hpp header provides operations on files and directories.

These operations traffic in paths; see boost/filesystem/path.hpp documentation.

For file I/O streams, see boost/filesystem/fstream.hpp documentation.

The Filesystem Library's Common Specifications apply to all member and non-member functions supplied by this header.

Header boost/filesystem/operations.hpp synopsis

namespace boost
{
  namespace filesystem
  {

    class directory_iterator
    {
    public:
      typedef path                     value_type;
      typedef std::ptrdiff_t           difference_type;
      typedef const path *             pointer;
      typedef const path &             reference;
      typedef std::input_iterator_tag  iterator_category;

      directory_iterator();
      explicit directory_iterator( const path & directory_ph );

      // Other_functions
      // ...
    };

    bool exists( const path & ph );
    bool symbolic_link_exists( const path & ph );
    bool is_directory( const path & ph );
    bool is_empty( const path & ph );
    bool equivalent( const path & ph1, const path & ph2 );

    boost::intmax_t file_size( const path & ph );

    std::time_t last_write_time( const path & ph );
    void last_write_time( const path & ph, std::time_t new_time );

    bool create_directory( const path & directory_ph );
    bool remove( const path & ph );
    unsigned long remove_all( const path & ph );
    void rename( const path & from_path,
                 const path & to_path );
    void copy_file( const path & source_file,
                    const path & target_file );

    const path & initial_path();
    path current_path();
    path complete( const path & ph,
                   const path & base = initial_path() );
    path system_complete( const path & ph );

  } // namespace filesystem
} // namespace boost

Class directory_iterator

Class directory_iterator provides a C++ standard conforming input iterator which accesses the contents of a directory.

The value type is boost::filesystem::path, so dereferencing a directory_iterator yields a path to a file or sub-directory contained within the directory represented by the directory-path argument supplied at construction. The path returned by dereferencing a directory_iterator is composed by appending the name of the directory entry to the directory path supplied at construction.

The order of the path entries returned by dereferencing successive increments of a directory_iterator is unspecified. Thus depending on the ordering provided by a particular implementation will result in non-portable code.

A path returned by dereferencing a directory_iterator is, if representing a directory, suitable for use as an argument to Filesystem Library functions specified as accepting paths or directory paths. If not representing a directory, the dereferenced path is suitable for use as an argument to Filesystem Library functions specified as accepting paths or file paths, or C++ Standard Library functions specified as taking file names. The leaf of a path returned by dereferencing a directory_iterator will never be ".." or ".".

Note: The implication of the above requirement is that if an operating system's directories can contain entries which are not usable by Filesystem Library or Standard Library functions, these entries will be skipped during directory iteration. Such entries are by definition non-portable, but can always be accessed via the native operating system API if required.

Warning: Programs performing directory iteration may wish to test, via exists(), if the path returned by dereferencing an iterator actually exists. It could be a symbolic link to a non-existent file or directory. Programs recursively walking directory trees for purposes of removing and renaming entries may wish to avoid following symbolic links, which can be detected with symbolic_link_exists().

Warning: If a file or sub-directory is removed from or added to a directory after the construction of a directory_iterator for the directory, it is unspecified whether or not subsequent incrementing of the iterator will ever result in an iterator whose value is the removed or added directory entry.

Constructors

directory_iterator();

Effects: Constructs a directory_iterator having the past-the-end value as described in the C++ standard, section 24.1.

explicit directory_iterator( const path & directory_ph );

Effects: Constructs a directory_iterator with a value representing the first path in directory_ph, or if empty(directory_ph), the past-the-end value.

Throws: if !exists( directory_ph )

Note: To iterate over the current directory, write directory_iterator(current_path()) rather than directory_iterator("").

Other functions

Class directory_iterator also supplies all the other functions required by the C++ standard clause 24 for input iterators, such as operator==, operator++, and operator*.

Non-member functions

The non-member functions provide common operations on files and directories. They follow traditional practice of the C and C++ standard libraries, except that they:

Rationale: Functions which already exist in the C++ Standard Library, such as remove() and rename(), retain the same names and general behavior in the Filesystem Library, to minimize surprises.

Rationale: Some errors which might at first glance appear to be preconditions are not specified as such, but instead will throw exceptions. This is because the possibility of race-conditions makes it unreliable to test for preconditions before calling the function. As a design practice, preconditions are not specified when it is not reasonable for a program to test for them before calling the function.

Empty path rationale: Some errors, particularly function arguments of empty paths, are specified both in Precondition and in Throws paragraphs. A non-empty path is specified as a precondition because an empty path is almost certainly an error, the error meets the usual criteria for Preconditions as specified in the C++ Standard clause 17, and user pre-detection of the error does not suffer from the precondition race problem described above. The error condition is also specified in the Throws paragraph to ensure that the error results in well-defined rather than implementation-defined behavior, and because existing practice for the equivalent operating system function is usually to treat an empty path as an error. The intended use of the Filesystem Library in script-like programs makes undefined behavior particularly unattractive.

Naming Rationale: See class path Naming Rationale.

exists

bool exists( const path & ph );

Returns: True if the operating system reports the path represented by ph exists, else false.

Note: Even if exists( ph ) == true, there is no guarantee that it will be possible to perform other operations on the file or directory. Access rights or other security concerns, for example, may cause other operations to fail.

Note: exists("") is valid and returns false;

symbolic_link_exists

bool symbolic_link_exists( const path & ph );

Returns: True if the operating system reports the path represented by  ph is present and is a symbolic link, else false.

Note: See the directory iterator warning for one use of symbolic_link_exists().

Note: The Microsoft Windows operating system does not currently support symbolic links, so symbolic_link_exists() always returns false on that platform. (Short-cut files (.lnk) are a Windows application feature, not an O/S feature.) Programmers should still test for symbolic links where applicable in case Windows adds the feature, and also so that programs will be portable to systems like POSIX, where symbolic links may be present.

Rationale: The function does not throw if ph is not present, and is accordingly named symbolic_link_exists rather than is_symbolic_link. Non-throwing behavior permits testing for all four possible conditions:

is_directory

bool is_directory( const path & ph );

Returns: True if the operating system reports the path represented by  ph is a directory, else false.

Throws: if !exists(ph)

Rationale: Treating !exists(ph) as an exception rather than just returning false came about because in real code !exists(ph) has often been the first indicate of a programming error.  A compound function returning exists(ph) && is_directory(ph) can always be added later.

is_empty

bool is_empty( const path & ph );

Returns: True if the operating system reports the path represented by  ph is an empty file or empty directory, else false.

Throws: if !exists(ph)

This function determines if the file or directory identified by the contents of ph is empty. To determine if a path string itself is empty, use the path::empty() function.

equivalent

bool equivalent( const path & ph1, const path & ph2 );

Returns: false if !exists(ph1) || !exists(ph2). Otherwise, returns true if ph1 and ph2 resolve to the same file or directory, else false. The criteria used to determine sameness are implementation defined:

Throws: if !exists(ph1) && !exists(ph2)

Warning: This function may be impossible to implement on some operating systems; users may wish to avoid use for code which may be ported to operating systems with limited filesystem support.

file_size

boost::intmax_t file_size( const path & ph );

Returns: The size of the file in bytes as reported by the operating system.

Throws: if !exists(ph) || is_directory(ph) || the file size cannot be determined (such as for an input stream).

Warming: If a compiler does not support maxint_t large enough to represent the operating system's maximum file size, or if the implementation does not know how to query the operating system for large file sizes, the returned value could be incorrect. This is not a problem with modern compilers on modern versions of Linux or Windows. Users on other platforms should build and run the file_size.cpp sample program against a large file to verify correct operation.

Rationale: Directories are excluded because the complexity of finding the size of a file is typically constant, while finding the size of a directory is typically linear. It was felt this would be surprising. The function is named accordingly. Users needing the size of a directory can trivially provide a user function which iterates over a directory returning a count.

last_write_time

Warning: The times associated with files are subject to many vicissitudes. Each type of filesystem differs slightly in the details and resolution of how times are recorded. The resolution is as low as one hour on some filesystems. It is not uncommon for a program to simultaneously have access to files maintained by FAT, ISO9660, NTFS, and POSIX filesystems, and so experience different last_write_time behavior for different files. During program execution, the system clock may be set to a new value by some other, possibly automatic, process. Another thread or process may write to a file, causing the last write time to change unexpectedly.

std::time_t last_write_time( const path & ph );

Returns: The time the file was last modified, as reported by the operating system. If the time cannot be determined, returns (std::time_t)(-1).

To convert the returned value to UTC or local time, use std::gmtime() or std::localtime() respectively.

Throws: if !exists(ph)

void last_write_time( const path & ph, std::time_t new_time );

Effects: Asks the operating system to set the last write time to new_time, or to the current time if new_time==std::time_t().

Throws: if !exists(ph)

Rationale: last_write_time(ph)==new_time is not specified as a postcondition because the times may differ somewhat on some operating systems.

create_directory

bool create_directory( const path & directory_ph );

Precondition: !directory_ph.empty()

Returns: The value of !exists( directory_ph ) prior to the establishment of the postcondition.

Postcondition: exists(directory_ph) && is_directory(directory_ph)

Throws: if directory_ph.empty() || (exists(directory_ph) && !is_directory(directory_ph)) || !exists(directory_ph/".."). See empty path rationale.

remove

bool remove( const path & ph );

Precondition: !ph.empty()

Returns: The value of exists( ph ) prior to the establishment of the postcondition.

Postcondition: !exists( ph )

Throws: if ph.empty() || (exists(ph) && is_directory(ph) && !is_empty(ph)). See empty path rationale.

Note: Symbolic links are themselves deleted, rather than what they point to being deleted.

Rationale: Does not throw when !exists( ph ) because not throwing:

There is, however, a slight decrease in safety because some errors will slip by which otherwise would have been detected. For example, a misspelled path name could go undetected for a long time.

The initial version of the library threw an exception when the path did not exist; it was changed to reflect user complaints.

remove_all

unsigned long remove_all( const path & ph );

Precondition: !ph.empty()

Postcondition: !exists( ph ) && !symbolic_link_exists( ph )

Returns: The number of files and directories removed.

Throws: if ph.empty(). See empty path rationale.

Note: Symbolic links are themselves deleted, rather than what they point to being deleted.

rename

void rename( const path & source, const path & target );

Precondition: !source.empty() && !target.empty()

Effects: Changes the name of  file or directory source to target. Specifically:

Source Target Result is "as if" these actions occur
!exists()   Throw filesystem_error. Note that !exists() covers the source.empty() case. [case 1]
  target.empty() Throw filesystem_error. See create_directory() rationale. [case 2]
  exists() Throw filesystem_error. [case 3]
!is_directory()   If !exists( target / ".." ) throw filesystem_error. [case 4A]
The source.leaf() name is changed to target.leaf(). [case 4B]
If source / ".." resolves to a different directory than target / "..", the renamed source file is moved there. [case 4C]
is_directory()   If !exists( target / ".." ) throw filesystem_error. [case 5A]
The source.leaf() name is changed to target.leaf(). [case 5B]
If system_complete(source.banch_path()) resolves to a different directory than system_complete(target.branch_path()),  the renamed source directory is moved there. [case 5C]

Postconditions: !exists(source) && exists(target), and the source file or directory contents and attributes are otherwise unchanged.

Throws: See Effects table above. See empty path rationale.

Rationale: Because rename is logically the same operation as move, there is no need for a separate move function. The choice of the name is based on existing practice in the C, C++, and POSIX libraries, and because the name move implies physical file movement, which does not in fact occur.

Note: Some operating systems with multiple roots do not allow rename operations between roots, and such an attempted rename with throw a filesystem_error exception.. Implementations should not take heroic efforts, such as switching to a copy mode, to make an otherwise failing rename succeed across roots.

Note: Symbolic links are themselves renamed, rather than what they point to being renamed.

copy_file

void copy_file( const path & source_file, const path & target_file );

Precondition: !source.empty() && !target.empty()

Effects: Copies the file represented by source_file to target_file.

Throws: if !exists(source_file) || is_directory(source_file) || exists(target_file) || target_file.empty() || !exists(to_file_path/"..")). See empty path rationale.

Note: File attributes are also copied. Specifically, POSIX stat::st_mode, and Windows BY_HANDLE_FILE_INFORMATION::dwFileAttributes.

initial_path

const path & initial_path();

Effects: The first time called, stores the path returned by current_path().

The preferred implementation would be to call initial_path() during program initialization, before the call to main(). This is, however, not possible with changing the C++ runtime library.

Returns: A reference to the stored path.

Rationale:  The semantics, in effect, turn a dangerous global variable into a safer global constant. The preferred implementation requires runtime library support, so alternate semantics are supplied for those implementations which cannot change an existing the runtime library.

Note: It is good practice for a program dependent on initial_path() to call it immediately upon entering main(). That protects against another function altering the current working directory (using a native platform function) before the first call to initial_path().

current_path

path current_path();

Returns: The current path as maintained by the operating system.

Postcondition: current_path().is_complete()

Note: The equivalent POSIX function is getcwd(). The equivalent Windows function is GetCurrentDirectoryA().

Warning: The current path maintained by the operating system is in-effect a dangerous global variable. It may be changed unexpectedly by a third-party or system library function, or by another thread. For a safer alternative, see initial_path().

Rationale: Although dangerous, the function is useful in dealing with other libraries. The current_path() name was chosen to emphasize that the function returns a complete path, not just a single directory name.

complete

path complete( const path & ph, const path & base = initial_path() );

Precondition: !ph.empty() && base.is_complete() && (ph.is_complete() || !ph.has_root_name())

Effects: Composes a complete path from ph and base, using the following rules:

For single-root operating systems (POSIX-like systems, for example), if ph.empty() or ph.is_complete(), the composed path is ph, otherwise the composed path is base/ph.

For multi-root operating systems (Windows, Classic Mac, many others), the rules are give by this table:

  ph.has_root_directory() !ph.has_root_directory()
ph.has_root_name() ph (precondition failure)
!ph.has_root_name() base.root_name()
/ ph
base / ph

Returns: The composed path.

Postcondition: For the returned path, p, p.is_complete() is true.

Throws: On precondition failure. See empty path rationale.

Note: When portable behavior is required, use complete(). When operating system dependent behavior is required, use system_complete().

Portable behavior is preferred when dealing with paths created internally within a program, particularly where the program should exhibit the same behavior on all operating systems.

Operating system dependent behavior is preferred when dealing with paths supplied by user input, reported to program users, or which should result in program behavior familiar to and expected by program users. The simple_ls.cpp program, for example, operates on a path supplied in the native operating system format, so uses  system_complete() to ensure that the path behaves as expected for the particular operating system.

Rationale: The !ph.has_root_name() portion of the precondition disallows the error condition of ph.root_name() being not equivalent to base.root_name(). The restriction is broader that would appear necessary, in that is also prohibits the case where they are equivalent. There is, however,  no portable way to express the root_name() equivalence requirement.

system_complete

path system_complete( const path & ph );

Precondition: !ph.empty()

Effects: Composes a complete path from ph, using the same rules used by the operating system to resolve a path passed as the filename argument to standard library open functions.

For POSIX-like systems, system_complete( ph ) has the same semantics as complete( ph, current_path() ).

For Widows, system_complete( ph ) has the same semantics as complete( ph, current_path() ) if ph.is_complete() || !ph.has_root_name() or ph and base have the same root_name(). Otherwise it acts like complete( ph, kinky ), where kinky is the current directory for the ph.root_name() drive. This will be the current directory of that drive the last time it was set, and thus may well be residue left over from some prior program run by the command processor! Although these semantics are often useful, they are also very error-prone, and certainly deserve to be called "kinky".

Returns: The composed path.

Postcondition: For the returned path, p, p.is_complete() is true.

Throws: If ph.empty(). See empty path rationale.

Note: See complete() note for usage suggestions.

Warning: This function relies on a global variable (current_path()), and so tends to be more error-prone than the similar function complete(). This function is doubly dangerous on Windows, where under cross-drive conditions it may be relying on a directory set by a prior program run by the command processor.


Revised 02 August, 2005

© Copyright Beman Dawes, 2002

Use, modification, and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at www.boost.org/LICENSE_1_0.txt)