tango.io.FilePath

License:
BSD style:

Version:
Oct 2004: Initial version

Version:
Nov 2006: Australian version

Version:
Feb 2007: Mutating version

Version:
Mar 2007: Folded FileProxy in

Version:
Nov 2007: VFS dictates '/' always be used

Version:
Feb 2008: Split file system calls into a struct

author:
Kris

FilePath provides a means to efficiently edit path components and to access the underlying file system.

Use module Path.d instead when you need pedestrian access to the file system, and are not mutating the path components themselves

class FilePath: tango.io.FilePath.PathView;
Models a file path. These are expected to be used as the constructor argument to various file classes. The intention is that they easily convert to other representations such as absolute, canonical, or Url.

File paths containing non-ansi characters should be UTF-8 encoded. Supporting Unicode in this manner was deemed to be more suitable than providing a wchar version of FilePath, and is both consistent & compatible with the approach taken with the Uri class.

FilePath is designed to be transformed, thus each mutating method modifies the internal content. See module Path.d for a lightweight immutable variation.

Note that patterns of adjacent '.' separators are treated specially in that they will be assigned to the name where there is no distinct suffix. In addition, a '.' at the start of a name signifies it does not belong to the suffix i.e. ".file" is a name rather than a suffix. Patterns of intermediate '.' characters will otherwise be assigned to the suffix, such that "file....suffix" includes the dots within the suffix itself. See method ext() for a suffix without dots.

Note that Win32 '\' characters are converted to '/' by default via the FilePath constructor.

alias Filter = bool delegate(FilePath, bool);
Filter used for screening paths via toList().

static FilePath opCall(char[] filepath = null);
Call-site shortcut to create a FilePath instance. This enables the same syntax as struct usage, so may expose a migration path.

this(char[] filepath = null);
Create a FilePath from a copy of the provided string.

FilePath assumes both path & name are present, and therefore may split what is otherwise a logically valid path. That is, the 'name' of a file is typically the path segment following a rightmost path-separator. The intent is to treat files and directories in the same manner; as a name with an optional ancestral structure. It is possible to bias the interpretation by adding a trailing path-separator to the argument. Doing so will result in an empty name attribute.

With regard to the filepath copy, we found the common case to be an explicit .dup, whereas aliasing appeared to be rare by comparison. We also noted a large proportion interacting with C-oriented OS calls, implying the postfix of a null terminator. Thus, FilePath combines both as a single operation.

Note that Win32 '\' characters are normalized to '/' instead.

final const const string toString();
Return the complete text of this filepath.

final const const @property FilePath dup();
Duplicate this path.

final inout inout(char)[] cString();
Return the complete text of this filepath as a null terminated string for use with a C api. Use toString instead for any D api.

Note that the nul is always embedded within the string maintained by FilePath, so there's no heap overhead when making a C call.

final inout @property inout(char)[] root();
Return the root of this path. Roots are constructs such as "C:".

final inout @property inout(char)[] folder();
Return the file path.

Paths may start and end with a "/". The root path is "/" and an unspecified path is returned as an empty string. Directory paths may be split such that the directory name is placed into the 'name' member; directory paths are treated no differently than file paths.

final inout @property inout(char)[] parent();
Returns a path representing the parent of this one. This will typically return the current path component, though with a special case where the name component is empty. In such cases, the path is scanned for a prior segment:
  • normal: /x/y/z => /x/y
  • special: /x/y/ => /x


Note that this returns a path suitable for splitting into path and name components (there's no trailing separator).

See pop() also, which is generally more useful when working with FilePath instances.

final inout @property inout(char)[] name();
Return the name of this file, or directory.

final @property char[] ext();
Ext is the tail of the filename, rightward of the rightmost '.' separator e.g. path "foo.bar" has ext "bar". Note that patterns of adjacent separators are treated specially; for example, ".." will wind up with no ext at all.

final inout @property inout(char)[] suffix();
Suffix is like ext, but includes the separator e.g. path "foo.bar" has suffix ".bar".

final inout @property inout(char)[] path();
Return the root + folder combination.

final inout @property inout(char)[] file();
Return the name + suffix combination.

final const const bool opEquals(Object o);
Returns true if all fields are identical. Note that some combinations of operations may not produce an identical set of fields. For example:
FilePath("/foo").append("bar").pop() == "/foo";
FilePath("/foo/").append("bar").pop() != "/foo/";


The latter is different due to variance in how append injects data, and how pop is expected to operate under different circumstances (both examples produce the same pop result, although the initial path is not identical).

However, opEquals() can overlook minor distinctions such as this example, and will return a match.

final const const bool opEquals(const(char)[] s);
Does this FilePath match the given text? Note that some combinations of operations may not produce an identical set of fields. For example:
FilePath("/foo").append("bar").pop() == "/foo";
FilePath("/foo/").append("bar").pop() != "/foo/";


The latter Is Different due to variance in how append injects data, and how pop is expected to operate under different circumstances (both examples produce the same pop result, although the initial path is not identical).

However, opEquals() can overlook minor distinctions such as this example, and will return a match.

final const const @property bool isAbsolute();
Returns true if this FilePath is *not* relative to the current working directory.

final const const @property bool isEmpty();
Returns true if this FilePath is empty.

final const const @property bool isChild();
Returns true if this FilePath has a parent. Note that a parent is defined by the presence of a path-separator in the path. This means 'foo' within "\foo" is considered a child of the root.

final FilePath replace(char from, char to);
Replace all 'from' instances with 'to'.

final @property FilePath standard();
Convert path separators to a standard format, using '/' as the path separator. This is compatible with URI and all of the contemporary O/S which Tango supports. Known exceptions include the Windows command-line processor, which considers '/' characters to be switches instead. Use the native() method to support that.

Note:
mutates the current path.

final @property FilePath native();
Convert to native O/S path separators where that is required, such as when dealing with the Windows command-line.

Note:
Mutates the current path. Use this pattern to obtain a copy instead: path.dup.native

final FilePath cat(const(char[])[] others...);
Concatenate text to this path; no separators are added.

See Also:
()

final FilePath append(const(char)[] path);
Append a folder to this path. A leading separator is added as required.

final FilePath prepend(const(char)[] path);
Prepend a folder to this path. A trailing separator is added if needed.

FilePath set(FilePath path);
Reset the content of this path to that of another and reparse.

final FilePath set(const(char)[] path, bool convert = false);
Reset the content of this path, and reparse. There's an optional boolean flag to convert the path into standard form, before parsing (converting '\' into '/').

final @property FilePath isFolder(bool folder);
Sidestep the normal lookup for paths that are known to be folders. Where folder is true, file system lookups will be skipped.

final @property FilePath root(const(char)[] other);
Replace the root portion of this path.

final @property FilePath folder(const(char)[] other);
Replace the folder portion of this path. The folder will be padded with a path-separator as required.

final @property FilePath name(const(char)[] other);
Replace the name portion of this path.

final @property FilePath suffix(const(char)[] other);
Replace the suffix portion of this path. The suffix will be prefixed with a file-separator as required.

final @property FilePath path(const(char)[] other);
Replace the root and folder portions of this path and reparse. The replacement will be padded with a path separator as required.

final @property FilePath file(const(char)[] other);
Replace the file and suffix portions of this path and reparse. The replacement will be prefixed with a suffix separator as required.

final FilePath pop();
Pop to the parent of the current filepath (in situ - mutates this FilePath). Note that this differs from parent() in that it does not include any special cases.

static char[] join(const(char[])[] paths...);
Join a set of path specs together. A path separator is potentially inserted between each of the segments.

final FilePath absolute(const(char)[] prefix);
Convert this FilePath to absolute format, using the given prefix as necessary. If this FilePath is already absolute, return it intact.

Returns this FilePath, adjusted as necessary.

static inout(char)[] stripped(inout(char)[] path, char c = FileConst.PathSeparatorChar);
Return an adjusted path such that non-empty instances do not have a trailing separator.

static inout(char[]) padded(inout(char[]) path, char c = FileConst.PathSeparatorChar);
Return an adjusted path such that non-empty instances always have a trailing separator.

static inout(char)[] prefixed(inout(char)[] s, char c = FileConst.PathSeparatorChar);
Return an adjusted path such that non-empty instances always have a prefixed separator.

final FilePath create();
Create an entire path consisting of this folder along with all parent folders. The path must not contain '.' or '..' segments. Related methods include PathUtil.normalize() and absolute().

Note that each segment is created as a folder, including the trailing segment.

Returns:
A chaining reference (this).

Throws:
IOException upon systen errors.

Throws:
IllegalArgumentException if a segment exists but as a file instead of a folder.

final FilePath[] toList(Filter filter = null);
List the set of filenames within this folder, using the provided filter to control the list:
bool delegate (FilePath path, bool isFolder) Filter;


Returning true from the filter includes the given path, whilst returning false excludes it. Parameter 'isFolder' indicates whether the path is a file or folder.

Note that paths composed of '.' characters are ignored.

static FilePath from(ref FileInfo info);
Construct a FilePath from the given FileInfo.

final inout @property bool exists();
Does this path currently exist?.

final const const @property Time modified();
Returns the time of the last modification. Accurate to whatever the OS supports, and in a format dictated by the file system. For example NTFS keeps UTC time, while FAT timestamps are based on the local time.

final const const @property Time accessed();
Returns the time of the last access. Accurate to whatever the OS supports, and in a format dictated by the file system. For example NTFS keeps UTC time, while FAT timestamps are based on the local time.

final const const @property Time created();
Returns the time of file creation. Accurate to whatever the OS supports, and in a format dictated by the file system. For example NTFS keeps UTC time, while FAT timestamps are based on the local time.

final FilePath rename(FilePath dst);
Change the name or location of a file/directory, and adopt the provided Path.

final inout inout(FilePath) copy(const(char)[] source);
Transfer the content of another file to this one. Returns a reference to this class on success, or throws an IOException upon failure.

final const const ulong fileSize();
Return the file length (in bytes).

final const const @property bool isWritable();
Is this file writable?

final const const @property bool isFolder();
Is this file actually a folder/directory?

final const const @property bool isFile();
Is this a regular file?

final const const Stamps timeStamps();
Return timestamp information.

Timstamps are returns in a format dictated by the file system. For example NTFS keeps UTC time, while FAT timestamps are based on the local time.

final inout inout(FilePath) copy(const(FilePath) src);
Transfer the content of another file to this one. Returns a reference to this class on success, or throws an IOException upon failure.

final inout inout(FilePath) remove();
Remove the file/directory from the file system.

final FilePath rename(const(char)[] dst);
change the name or location of a file/directory, and adopt the provided Path.

final inout inout(FilePath) createFile();
Create a new file.

final inout inout(FilePath) createFolder();
Create a new directory.

final const const int opApply(scope int delegate(ref FileInfo) dg);
List the set of filenames within this folder.

Each path and filename is passed to the provided delegate, along with the path prefix and whether the entry is a folder or not.

Returns the number of files scanned.

abstract interface PathView;
Examples:
version(Win32)
{
assert (FilePath("/foo".dup).append("bar").pop() == "/foo");
assert (FilePath("/foo/".dup).append("bar").pop() == "/foo");

auto fp = new FilePath(r"C:/home/foo/bar".dup);
fp ~= "john";
assert (fp == r"C:/home/foo/bar/john");
fp.set (r"C:/");
fp ~= "john";
assert (fp == r"C:/john");
fp.set("foo.bar");
fp ~= "john";
assert (fp == r"foo.bar/john");
fp.set("");
fp ~= "john";
assert (fp == r"john");

fp.set(r"C:/home/foo/bar/john/foo.d".dup);
assert (fp.pop() == r"C:/home/foo/bar/john");
assert (fp.pop() == r"C:/home/foo/bar");
assert (fp.pop() == r"C:/home/foo");
assert (fp.pop() == r"C:/home");
assert (fp.pop() == r"C:");
assert (fp.pop() == r"C:");

// special case for popping empty names
fp.set (r"C:/home/foo/bar/john/".dup);
assert (fp.parent == r"C:/home/foo/bar");

fp = new FilePath;
fp.set (r"C:/home/foo/bar/john/".dup);
assert (fp.isAbsolute);
assert (fp.name == "");
assert (fp.folder == r"/home/foo/bar/john/");
assert (fp == r"C:/home/foo/bar/john/");
assert (fp.path == r"C:/home/foo/bar/john/");
assert (fp.file == r"");
assert (fp.suffix == r"");
assert (fp.root == r"C:");
assert (fp.ext == "");
assert (fp.isChild);

fp = new FilePath(r"C:/home/foo/bar/john".dup);
assert (fp.isAbsolute);
assert (fp.name == "john");
assert (fp.folder == r"/home/foo/bar/");
assert (fp == r"C:/home/foo/bar/john");
assert (fp.path == r"C:/home/foo/bar/");
assert (fp.file == r"john");
assert (fp.suffix == r"");
assert (fp.ext == "");
assert (fp.isChild);

fp.pop();
assert (fp.isAbsolute);
assert (fp.name == "bar");
assert (fp.folder == r"/home/foo/");
assert (fp == r"C:/home/foo/bar");
assert (fp.path == r"C:/home/foo/");
assert (fp.file == r"bar");
assert (fp.suffix == r"");
assert (fp.ext == "");
assert (fp.isChild);

fp.pop();
assert (fp.isAbsolute);
assert (fp.name == "foo");
assert (fp.folder == r"/home/");
assert (fp == r"C:/home/foo");
assert (fp.path == r"C:/home/");
assert (fp.file == r"foo");
assert (fp.suffix == r"");
assert (fp.ext == "");
assert (fp.isChild);

fp.pop();
assert (fp.isAbsolute);
assert (fp.name == "home");
assert (fp.folder == r"/");
assert (fp == r"C:/home");
assert (fp.path == r"C:/");
assert (fp.file == r"home");
assert (fp.suffix == r"");
assert (fp.ext == "");
assert (fp.isChild);

fp = new FilePath(r"foo/bar/john.doe".dup);
assert (!fp.isAbsolute);
assert (fp.name == "john");
assert (fp.folder == r"foo/bar/");
assert (fp.suffix == r".doe");
assert (fp.file == r"john.doe");
assert (fp == r"foo/bar/john.doe");
assert (fp.ext == "doe");
assert (fp.isChild);

fp = new FilePath(r"c:doe".dup);
assert (fp.isAbsolute);
assert (fp.suffix == r"");
assert (fp == r"c:doe");
assert (fp.folder == r"");
assert (fp.name == "doe");
assert (fp.file == r"doe");
assert (fp.ext == "");
assert (!fp.isChild);

fp = new FilePath(r"/doe".dup);
assert (fp.isAbsolute);
assert (fp.suffix == r"");
assert (fp == r"/doe");
assert (fp.name == "doe");
assert (fp.folder == r"/");
assert (fp.file == r"doe");
assert (fp.ext == "");
assert (fp.isChild);

fp = new FilePath(r"john.doe.foo".dup);
assert (!fp.isAbsolute);
assert (fp.name == "john.doe");
assert (fp.folder == r"");
assert (fp.suffix == r".foo");
assert (fp == r"john.doe.foo");
assert (fp.file == r"john.doe.foo");
assert (fp.ext == "foo");
assert (!fp.isChild);

fp = new FilePath(r".doe".dup);
assert (!fp.isAbsolute);
assert (fp.suffix == r"");
assert (fp == r".doe");
assert (fp.name == ".doe");
assert (fp.folder == r"");
assert (fp.file == r".doe");
assert (fp.ext == "");
assert (!fp.isChild);

fp = new FilePath(r"doe".dup);
assert (!fp.isAbsolute);
assert (fp.suffix == r"");
assert (fp == r"doe");
assert (fp.name == "doe");
assert (fp.folder == r"");
assert (fp.file == r"doe");
assert (fp.ext == "");
assert (!fp.isChild);

fp = new FilePath(r".".dup);
assert (!fp.isAbsolute);
assert (fp.suffix == r"");
assert (fp == r".");
assert (fp.name == ".");
assert (fp.folder == r"");
assert (fp.file == r".");
assert (fp.ext == "");
assert (!fp.isChild);

fp = new FilePath(r"..".dup);
assert (!fp.isAbsolute);
assert (fp.suffix == r"");
assert (fp == r"..");
assert (fp.name == "..");
assert (fp.folder == r"");
assert (fp.file == r"..");
assert (fp.ext == "");
assert (!fp.isChild);

fp = new FilePath(r"c:/a/b/c/d/e/foo.bar".dup);
assert (fp.isAbsolute);
fp.folder (r"/a/b/c/");
assert (fp.suffix == r".bar");
assert (fp == r"c:/a/b/c/foo.bar");
assert (fp.name == "foo");
assert (fp.folder == r"/a/b/c/");
assert (fp.file == r"foo.bar");
assert (fp.ext == "bar");
assert (fp.isChild);

fp = new FilePath(r"c:/a/b/c/d/e/foo.bar".dup);
assert (fp.isAbsolute);
fp.folder (r"/a/b/c/d/e/f/g/");
assert (fp.suffix == r".bar");
assert (fp == r"c:/a/b/c/d/e/f/g/foo.bar");
assert (fp.name == "foo");
assert (fp.folder == r"/a/b/c/d/e/f/g/");
assert (fp.file == r"foo.bar");
assert (fp.ext == "bar");
assert (fp.isChild);

fp = new FilePath(r"C:/foo/bar/test.bar".dup);
assert (fp.path == "C:/foo/bar/");
fp = new FilePath(r"C:\foo\bar\test.bar".dup);
assert (fp.path == r"C:/foo/bar/");

fp = new FilePath("".dup);
assert (fp.isEmpty);
assert (!fp.isChild);
assert (!fp.isAbsolute);
assert (fp.suffix == r"");
assert (fp == r"");
assert (fp.name == "");
assert (fp.folder == r"");
assert (fp.file == r"");
assert (fp.ext == "");
/+
fp = new FilePath(r"C:/foo/bar/test.bar");
fp = new FilePath(fp.asPath ("foo"));
assert (fp.name == r"test");
assert (fp.folder == r"foo/");
assert (fp.path == r"C:foo/");
assert (fp.ext == ".bar");

fp = new FilePath(fp.asPath (""));
assert (fp.name == r"test");
assert (fp.folder == r"");
assert (fp.path == r"C:");
assert (fp.ext == ".bar");

fp = new FilePath(r"c:/joe/bar");
assert(fp.cat(r"foo/bar/") == r"c:/joe/bar/foo/bar/");
assert(fp.cat(new FilePath(r"foo/bar")).toString == r"c:/joe/bar/foo/bar");

assert (FilePath.join (r"a/b/c/d", r"e/f/" r"g") == r"a/b/c/d/e/f/g");

fp = new FilePath(r"C:/foo/bar/test.bar");
assert (fp.asExt(null) == r"C:/foo/bar/test");
assert (fp.asExt("foo") == r"C:/foo/bar/test.foo");
+/
}


abstract const const immutable(char)[] toString();
Return the complete text of this filepath.

inout inout(char)[] cString()();
Return the complete text of this filepath.

abstract inout @property inout(char)[] root();
Return the root of this path. Roots are constructs such as "C:".

abstract inout @property inout(char)[] folder();
Return the file path. Paths may start and end with a "/". The root path is "/" and an unspecified path is returned as an empty string. Directory paths may be split such that the directory name is placed into the 'name' member; directory paths are treated no differently than file paths.

abstract inout @property inout(char)[] name();
Return the name of this file, or directory, excluding a suffix.

abstract @property char[] ext();
Ext is the tail of the filename, rightward of the rightmost '.' separator e.g. path "foo.bar" has ext "bar". Note that patterns of adjacent separators are treated specially; for example, ".." will wind up with no ext at all.

abstract inout @property inout(char)[] suffix();
Suffix is like ext, but includes the separator e.g. path "foo.bar" has suffix ".bar".

abstract inout @property inout(char)[] path();
Return the root + folder combination.

abstract inout @property inout(char)[] file();
Return the name + suffix combination.

abstract const const @property bool isAbsolute();
Returns true if this FilePath is *not* relative to the current working directory.

abstract const const @property bool isEmpty();
Returns true if this FilePath is empty.

abstract const const @property bool isChild();
Returns true if this FilePath has a parent.

abstract inout @property bool exists();
Does this path currently exist?

abstract const const @property Time modified();
Returns the time of the last modification. Accurate to whatever the OS supports.

abstract const const @property Time accessed();
Returns the time of the last access. Accurate to whatever the OS supports.

abstract const const @property Time created();
Returns the time of file creation. Accurate to whatever the OS supports.

abstract const const @property ulong fileSize();
Return the file length (in bytes).

abstract const const @property bool isWritable();
Is this file writable?

abstract const const @property bool isFolder();
Is this file actually a folder/directory?

abstract const const @property Stamps timeStamps();
Return timestamp information.


Page generated by Ddoc. Copyright (c) 2004 Kris Bell. All rights reserved