Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Table of Contents

  1. FilePath
  2. File
  3. FileSystem
  4. FileRoots

Operations with the file system

This page describes the operations that request information about the file system or do actions to it.

FilePath

In the Tango library, file and directory locations are usually described by a FilePath instance. Those methods accepting a char[] instead will often wrap it with a FilePath before continuing.

FilePath itself exposes the constituent components of the file-path as distinct elements, and performs a variety of transformations upon the original path. Methods are available to return the path portion, the file name, the file extension, file suffix (which may have multiple dots) and so on. Transformations support the replacement of one or more components, and return a complete file-path as a char[] rather than another FilePath instance. The latter is specifically to support the use of stack-based class instances.

FilePath assumes both path and name are present within the provided file-path, and therefore may split what is otherwise a logically valid path. That is, the name attribute of a FilePath is considered to be the segment following a rightmost path-separator; therefore a directory identifier may be mapped to the name instead of explicitly remaining with the path attribute. This follows the intent of treating files and directories in an identical manner – as a name with an optional ancestral structure. However, where this is not desired it is possible (and legitimate) to bias the interpretation by adding a trailing path-separator. Doing so will result in an empty name attribute and a longer path attribute.

When a FilePath is created, it usually makes a copy of the provided file-path argument. Prior experience with a non-copying implementation had shown the common case to be an explicit .dup on the argument, whereas aliasing appeared to be rare by comparison. It was also noted that a large proportion were used for interaction with C-oriented OS calls, implying the postfix of a null terminator. FilePath combines both operations as part of the generic constructor, whilst leaving an option open to alias where appropriate.

source:/trunk/doc/images/classdia.tango.io.FilePath.png

FilePath is intended to be mutable, thus each transformation modifies the internal content. There is a read-only view of FilePath (PathView) that can be used to expose an immutable perspective. The current class-based implementation will likely migrate to a struct version once the D language gains support for struct-constructors (see module tango.io.Path for more information).

A number of common file and directory operations are exposed via FilePath, including creation, renaming, removal, and folder/directory content listing. A handful of attributes such as file size and various timestamps are also made available.

Creating a FilePath is straightforward; provide the constructor with a char[]. File paths containing non-ANSI characters should be UTF-8 encoded:

auto path = new FilePath ("name");

Creating files and folders require distinction between the two. For files, use:

path.create;

Folders should be created using:

path.createFolder;

Renaming a file can also move it from one place to another:

path.rename ("/directory/otherfilename");

Copying a file retains the original timestamps:

path.copy ("source.name");

Removal of a file or a folder:

path.remove;

Listing the content of a folder:

foreach (name; path.toList)
         // do something with the contained  file or folder  name

There’s an additional, lower-level toList() which exposes further control via a delegate:

path.toList (bool delegate (FilePath path, bool isFolder) dg);

This version of toList() can be used to construct custom file visitors.

FilePath Exceptions

IO exceptions are raised where the underlying OS detects an error. For example, attempting to remove a non-existent or read-only file will generate an exception.

File

The principal means of file access is via a File, providing both streaming and random-access to file content. Opening a file for reading is performed as follows:

auto conduit = new File ("myFilePath");

Whereas opening a file for writing requires one of the file styles to be specified:

auto conduit = new File ("myFilePath", File.WriteCreate);

There are a variety of pre-defined styles, including appending, read-only, read-write, create-always and so on. Additional styles can be defined, using a combination of a dozen system-level flags.

File enables direct, type-agnostic access to file content. In this example we copy a file directly to the console:

// open a file for reading
auto from = new File ("test.txt");

// display file content on console
Stdout.stream.copy (from);

And here we copy one file to another:

// open a file for reading
auto from = new File ("test.txt");

// open another for writing
auto to = new File ("copy.txt", File.WriteCreate);

// copy file
to.output.copy (from);

To load an entire file into memory, one might consider the following:

// open file for reading 
auto file = new File ("test.txt");

// create an array to house the entire file
auto content = new char[file.length];

// read the file content. Return value is the number of bytes read 
auto bytesRead = file.input.read (content);

Conversely, one may write directly to a File, like so:

// open file for writing 
auto to = new File ("text.txt", File.WriteCreate);

// write an array of content to it 
auto bytesWritten = to.output.write (content);

File supports random IO also. In this example we relocate the current file position using seek() and, to add a little spice, utilize a Data stream (reader & writer pair) to perform simple typed input and output:

// open a file for reading and writing
auto file = new File ("random.bin", File.ReadWriteCreate);

// bind a Data stream to this conduit 
auto input  = new DataInput  (file);
auto output = new DataOutput (file);

int    x = 10;
char[] y = "hello";

// write data, and flush output since Data IO is buffered 
output.int32 (x);
output.array (y);
output.flush;

// rewind to file start
file.seek (0);

// read data back again
x = input.int32;
y = input.array;

Note that in the above example we are using buffered IO, via the Data stream, and thus need to flush the output before relocating the current position.

Each File should be explicitly closed when no longer needed. It can often be convenient to use a scope expression for this purpose:

scope file = new File ("myFilePath");

As a convenience, File has static functions to read, write or append. For example, to read all file content:

auto content = File.get ("myfile");

The underlying file is closed before the call returns. File must avoid making assumptions about the file content, so the above example returns an array of void. When working with text files, it is necessary to cast the return value to represent the correct data type. For text files this is often a char[]:

auto content = cast(char[]) File.get ("myfile");

To convert a text file into a set of lines, try the following:

import Text = tango.text.Util;

auto content = cast(char[]) File.get ("myfile");
auto lines = Text.splitLines (content);

Using a foreach to iterate instead:

foreach (line; Text.lines (cast(char[]) File.get("myfile"))
         // do something with each line

Files can be set to the content of an array:

char[] myText;

File.set ("myfile", myText);

File content may be appended in a similar fashion:

char[] myText;

File.append ("myfile", myText);

source:/trunk/doc/images/classdia.tango.io.FileConduit.png

File Exceptions

IO exceptions are raised where a bulk read or write operation fails entirely, or where a copy operation fails to complete. This might happen when, for example, attempting to write a read-only file.

FileSystem

This is where various file-system controls are exposed. At this time, FileSystem provides facilities for retrieving and setting the current working directory, and for converting a path into its absolute form. To access the current directory name:

auto name = FileSystem.getDirectory;

Changing the current directory is similar.

Method absolutePath accepts a FilePath instance, and converts it into absolute form relevant to the current working directory. Absolute form generally begins with a path separator, or a storage device identifier, and contains no instances of '.' or '..' anywhere in the path. Where the provided path is already absolute, it is returned untouched.

FileSystem Exceptions

Failing to set or retrieve the current directory will cause an exception to be thrown. Passing an invalid path to absolutePath will also result in an exception being thrown.

FileRoots

The storage-devices of the file-system are exposed here. On Win32, roots represent drive letters, whilst on linux they represent devices located via /etc/mtab/. To list the file storage devices available:

foreach (name; FileRoots.list)
         // do something with each name

FileRoots Exceptions

IO exceptions will be throws where an underlying OS or file-system error occurs.