D Programming Language Tutorial
Ali Çehreli



İngilizce Kaynaklar

Diğer



Files

We have seen in the previous chapter that standard input and output streams can be redirected to and from files and other programs with the >, <, and | operators on the console. Despite being very powerful, these tools are not suitable in every situation because in many cases programs can not complete their tasks by reading from their input and writing to their output like a simple pipe.

For example, a program that deals with student records may use its standard output to display the program menu. Such a program would need to write the student records to an actual file instead of stdout.

In this chapter, we will cover reading from and writing to files of file systems.

Fundamental concepts

Files are represented by the File struct of the std.stdio module. Since I haven't introduced structs yet, we will have to accept the syntax of struct construction as-is for now.

Before getting to code samples we have to go through fundamental concepts about files.

The producer and the consumer

Files that are created on one platform may not be readily usable on other platforms. Merely opening a file and writing data in it may not be sufficient for that data to be available on the consumer's side. The producer and the consumer of the data must have already agreed on the format of the data that is in the file. For example, if the producer has written the id and the name of the student records in a certain order, the consumer must read the data back in the same order.

Additionally, the sample codes below do not write BOM to the beginning of the file. This may make your files incompatible with systems that require BOM. (BOM is short for byte order mark. It specifies in what order the UTF code units of characters are arranged in a file.)

Access rights

File systems present files to programs under certain access rights. Access rights are important for both data integrity and performance.

When it is about reading, allowing multiple programs read from the same file would improve performance because no program would be waiting for any other to finish their reading. On the other hand, when it is about writing, only one program should be allowed to write to a file, otherwise programs may overwrite each other's data.

Opening a file

The standard input and output streams stdin and stdout are already open when programs start running. They are ready to be used.

On the other hand, files must first be opened by specifying the name of the file and the access rights that are needed.

Closing a file

Any file that has been opened by a program must be closed when the program finishes using that file. In most cases the files need not be closed explicitly; they are closed automatically when File objects are terminated automatically:

if (aCondition) {

    // Assume a File object has been created and used here.
    // ...

} // ← The actual file would be closed automatically here
  //   when leaving this scope. No need to close explicitly.

In some cases a file object may need to be re-opened to access a different file or the same file with different access rights. In such cases the file must be closed and re-opened:

    file.close();
    file.open("student_records", "r");
Writing to and reading from files

Since files are character streams, input and output functions writeln, readf, etc. are used exactly the same way with them. The only difference is that the name of the File variable and a dot must be typed:

    writeln("hello");        // writes to standard output
    stdout.writeln("hello"); // same as above
    file.writeln("hello");   // writes to the specified file
eof() to determine the end of a file

The eof() member function determines whether the end of a file has been reached while reading from a file. It returns true if the end of the file has been reached.

For example, the following loop will be active until the end of the file:

    while (!file.eof()) {
        /* ... */
    }
The std.file module

The std.file module contains functions and types that are useful when working with contents of directories. For example, exists can be used to determine whether a file or a directory exists on the file systems:

import std.file;

// ...

    if (exists(fileName)) {
        // there is a file or directory under that name

    } else {
        // no file or directory under that name
    }
std.stdio.File struct

File uses the same mode characters that are used by fopen of the C programming language:

 Mode  Definition
rread access
the file is opened to be read from the beginning
r+read and write access
the file is opened to be read from and written at the beginning
wwrite access
if the file does not exist, it is created as empty
if the file already exists, its contents are cleared
w+read and write access
if the file does not exist, it is created as empty
if the file already exists, its contents are cleared
aappend access
if the file does not exist, it is created as empty
if the file already exists, its contents are preserved and it is opened to be written at the end
a+read and append access
if the file does not exist, it is created as empty
if the file already exists, its contents are preserved and the file is opened to be read from the beginning and written at the end

A 'b' character may be added to the mode string as in "rb". This may have an effect on platforms that support the binary mode, but it is ignored on all POSIX systems.

The File struct is included in the std.stdio module.

Writing to a file

The file must have been opened in one of the write modes first:

import std.stdio;

void main()
{
    File file = File("student_records", "w");

    file.writeln("Name  : ", "Zafer");
    file.writeln("Number: ", 123);
    file.writeln("Class : ", "1A");
}

As you remember from the Strings chapter, the type of literals like "student_records" is string, consisting of immutable characters. For that reason, it is not possible to construct File objects by a mutable file name (e.g. char[]). When needed, it would be necessary to call the .idup property of the mutable string.

The program above creates or overwrites the contents of a file named student_records in the directory that it has been started under (in the program's working directory).

Note: File names can contain any character that is legal for that file system. To be portable, I will use only ASCII characters.

Reading from a file

The file must have been opened in one of the read modes first:

import std.stdio;
import std.string;

void main()
{
    File file = File("student_records", "r");

    while (!file.eof()) {
        string line = chomp(file.readln());
        writeln("read line -> |", line);
    }
}

The program above reads all of the lines of the file named student_records and prints those lines to its standard output.

Exercise