3.1 Basic Patterns of Use

The basic idea of how to use files in Mozart is as follows. We provide a class Open.file. To an object created from this class we refer to as file object. Conceptually, its state consists of a string together with the current position in this string called seek pointer.

In the following, we will refer to this particular string as file. It is visible to other operating system processes via the operating system's filesystem.

The atoms used for labels and fields of methods of the class Open.file are chosen to coincide with the common operating system terminology (i. e., POSIX terminology).

3.1.1 Reading a File

Suppose we want to read data from a file named a.txt. The contents of this file is as follows1:

0

1

2

3

4

5

6

7

8

9

0

H

e

l

l

o

H

e

l

l

o

10

O

z

_

I

s

_

b

e

a

u

20

t

i

f

u

l

The first step is to create a file object and associate it to the file a.txt. This is done by feeding

F={New Open.file init(name:'a.txt' flags:[read])}

The list [read] used as value of the field flags means that we want to have read access to the file.

After the file has been opened and associated to the file object F, we can read from it. To read the next five characters from the file we feed

{F read(list:{Browse} size:5)}

The character string Hello appears in the browser window (the value 5 at the field size signals that we want to read five characters from the file).

Note that if we had not switched the browser to the mode for displaying virtual strings (see Chapter 2), we would have seen the output [72 101 108 108 111] in the browser window.

A common pattern of use is to read the entire file into an Oz string. This is especially supported. Feed:

{F read(list:{Browse} size:all)}

The rest of the file HelloOz is beautiful appears in the browser window.

Up to now we have read the data in strict left to right fashion. Suppose we want to start reading at the eighth character of the file. Navigating to this character and reading the following five characters is done by:

{F seek(whence:set offset:7)}
{F read(list:{Browse} size:5)}

You will see lloOz in the browser window. Internally, as already mentioned, each file object has a seek pointer. Each operation refers to its position: for instance, instead of ``reading five characters'' one should think of ``reading the next five characters after the seek pointer''. Note that in order to read the first character of a file, the seek pointer must be set to the offset zero.

Furthermore, you can get the current position of the seek pointer by:

{F tell(offset:{Browse})}

The number 12 appears in the browser window.

3.1.2 Closing a File

After use, the file object F must be closed. By applying F to the message close:

{F close}

the file as well as the file object are closed. Note that invoking a method other than close of the class Open.file after the object has been closed raises an exception. Exceptions are discussed later.

3.1.3 Writing a File

Suppose we want to create an object for a file which does not yet exist and that should be named ours.txt. Furthermore, this file should have read and write access rights for yourself and for each member of your group. We feed

F={New Open.file  
       init(name:  'ours.txt' 
            flags: [write create]
            mode:  mode(owner: [read write]  
                        group: [read write]))}

Data to be written to the file must be virtual strings. For example, the character sequence "Go ahead" can be written to the file F by

{F write(vs:'Go ahead!')}

The same character sequence we also can write by

{F write(vs:"Go ahead!")}

Also more complex virtual strings are handled this way. For example

{F write(vs:"This is "#1#' And '# 
            ("now a float: "#2.0)#"\n")}

writes a nested virtual string containing integers, atoms, strings and floats to the file. Even the filename argument of the init method of class Open.file is allowed to be a virtual string. For more information on virtual strings see Section 2.2.

If you type the Unix command

cat ours.txt

or the Windows command

type ours.txt

to a shell, you see the content of ours.txt printed to standard output.

3.1.4 Exceptions

Functionality provided by the class Open.file relies on operating system services. These services might report exceptions, these exceptions are then raised as Oz exceptions.

For example, trying to open a non existing file raises an exception. Operating system dependent exceptions can be caught as follows:

try 
   _={New Open.file init(name:'not-existing')}
catch system(os(A W I S) ...then 
   {Browse os(category:    A
              what:        W
              number:      I
              description: S)}
end

where A is an atom describing the category of the error (e. g., os or host), W the system call that raised the exception (as string), I is the operating system dependent error number, and S is a string describing the error.

Besides of operating system exceptions, the methods of the class Open.file can raise two different exceptions themselves:

  1. An exception is raised when an object is initialized twice. This exception can be caught as follows:

    try 
       
    ... % Initialize twice
    catch system(open(alreadyInitialized O M) ...then 
       
    ... 
    end

    Here O is the object that has been tried to be initialized twice by applying it to the method M.

  2. An exception is raised when a message other than close is executed by an already closed file object. This exception can be caught as follows:

    try 
       
    ... % Apply closed object
    catch system(open(alreadyClosed O M) ...then 
       
    ... 
    end

    Here O is the object that has been closed already and M the message O has been applied to.


1. The demo file for this document contains the Oz code to create this file.

Christian Schulte
Version 1.4.0 (20080702)