Next: Self and super, Previous: Basic classes, Up: Top [Index]
This chapter describes how Ctalk performs basic file operations - opening, closing, reading, and writing files.
There are three classes that provide file input and output:
ReadFileStream,
which implements objects and methods for
reading from files, WriteFileStream,
which provides methods and
objects for writing to files, and their superclass, FileStream,
which provides methods and class definitions that are common to both
reading and writing files. There is also a DirectoryStream
class, which this chapter describes below.
Ctalk provides many of the same facilities that C’s stdio.h
library functions provide, although the language implements them as
objects.
Here is an example that shows how to use the openOn
method
(class ReadFileStream
).
ReadFileStream new myInput; myInput openOn "myFileName";
If the program was able to to open the file, you can then read input
from the myInput
stream.
We should note here that Ctalk also provides classes and methods that
handle file I/O errors. We will deal with them later on. If you
need to see how to catch file I/O errors right now, look at some of
the example programs in the Ctalk package, especially ctwc.c.
Opening a file for output is similar to opening a file for input,
except that the stream is an instance of class WriteFileStream.
WriteFileStream new myOutput; myOutput openOn "outputFileName";
After a program has opened the file streams successfully, you can read and write from them with the following methods.
Operation Reading Writing --------- ------- ------- Read or write one character. readChar writeChar Read or write one line. readLine - Read or write all the data. readAll writeStream Read or write formatted data. readFormat printOn Read fixed length data. readRec
Here is a simple example that shows opening a file, and reading each character.
ReadFileStream new inputChars; Character new c; inputChars openOn "inputFileName"; while ((c = inputChars readChar) != EOF) printf ("%c", c);
When readChar
reaches the end of a file, it returns an
EOF
character, which is ‘-1’ on most systems.
Using the method streamEof
(class FileStream
) to check for the
end of the input is slightly more reliable than looking for an
EOF
character, because it distinguishes the end of the input
caused by an error from the end of the input caused by reaching the
end of a file.
ReadFileStream new inputChars; Character new c; inputChars openOn "inputFileName"; while (TRUE) { /* Loop until the end of the input. */ c = inputChars readChar; if (inputChars streamEof) break; }
If you don’t need to examine each character as it is read, however,
then you can simply use readAll
(class ReadFileStream
),
which provides the complete input as a String
object.
ReadFileStream new inputStream; String new inputString; inputStream openOn "myInput"; inputString = inputStream readAll; printf ("%s", inputString);
Simple applications can use the methods readLine
(class
ReadFileStream
) and writeStream
(class WriteFileStream
)
together to process input.
Here is a portion of the program ctrep.c.
You find the program in
the Ctalk package. It checks the input for occurrences of a character
string, and replaces the string before writing the output.
/* * Loop until the end of input. */ while (TRUE) { line = stdinStream readLine; if (stdinStream streamEof) break; inputLineLength = line length; word = ""; for (i = 0; i < inputLineLength; i = i + 1) { inputChar = line at i; if (inputChar isSpace) { if (word == pattern) { stdoutStream writeStream replacement; } else { stdoutStream writeStream word; } stdoutStream writeStream inputChar; word = ""; } else { word = word + inputChar asString; } } }
Notice that the previous example used stdinStream
and
stdoutStream
as its input and output streams.
These two objects are class variables of ReadFileStream
and
WriteFileStream,
respectively. They represent the program’s
standard input (stdin
) and standard output (stdout
) file
streams.
Because ctrep.c
is a filter program, it uses these two streams
instead of streams that work with normal files.
Class WriteFileStream
also implements the stderrStream
class variable, which represents the application’s standard error
(stderr
) stream.
You should notice, also, that most of the examples so far have used
printf
to print output. You can accomplish the same task with
the following Ctalk statement.
stdoutStream writeStream "Hello, world!\n";
This is equivalent to:
printf ("Hello, world!\n");
Ctalk initializes stdinStream
automatically when the program
creates the first ReadFileStream
object, and it initializes
stdoutStream
and stderrStream
when the program creates
the first WriteFileStream
object.
If the program simply needs to use stdinStream,
stdoutStream,
or stderrStream
without opening files,
then it can call the class method classInit
with either the
class ReadFileStream
or WriteFileStream
as the receiver.
ReadFileStream classInit; /* Initialize stdinStream. */ WriteFileStream classInit; /* Initialize stdoutStream and stderrStream. */
Here is the example from the previous chapter that printed elements of
arrays. This version uses stdoutStream
to output the array
elements.
Array instanceMethod printArrayElement (void) { WriteFileStream classInit; stdoutStream writeStream self; return NULL; } int main () { Array new myArray; myArray atPut 0, "My"; myArray atPut 1, "name"; myArray atPut 2, "is"; myArray atPut 3, "Bill"; myArray map printArrayElement; printf ("\n"); myArray atPut 3, "Joe"; myArray map printArrayElement; printf ("\n"); }
The printArrayElement
method initializes class
WriteFileStream.
You need to perform the class initialization
before the class is first used in the program. There is no problem
with calling classInit
multiple times, however, because the
method checks to determine if the class is already initialized.
The class DirectoryStream
provides the methods mkDir
and
rmDir
which create and delete directories. The methods function
exactly as their C library counterparts, except that they raise a
SystemErrnoException
on error and return an Integer
with
the value -1
.
Ctalk uses 0755
(‘drwxr-xr-x’) as the default mode for new
directories. Programs can change that value by redefining the macro
CTALK_DIRECTORY_MODE
.
Here is a program that creates a new directory.
/* * Define more restrictive permissions for * new directories. Undefine the macro first * to avoid a warning message. */ #undef CTALK_DIRECTORY_MODE #define CTALK_DIRECTORY_MODE 0700 int main () { DirectoryStream new thisDir; thisDir mkDir "testDir"; }
The rmDir
method works similarly to the mkDir
method.
int main () { DirectoryStream new thisDir; thisDir rmDir "testDir"; }
The C99 standard requires that stdin,
stdout,
and stderr
should be implemented as macros, which on
some systems (notably Solaris) causes problems with
C-to-object translation.
If Ctalk cannot register the macros as C variables, then you
must call C functions like sscanf(3) and
fscanf(3) with only C variables, or use a method
with stdoutStream
or stderrStream
(WriteFileStream
class), or stdinStream
(ReadFileStream
class).
The method consoleReadLine
(in class String
) prints a
prompt string, and then waits for you to enter a line of text. What
makes this method special is that it uses the GNU readline library’s
standard command editing and history features, if you built Ctalk with
readline support (see the options to the configure script for
details). In that case, Ctalk also defines the
HAVE_GNU_READLINE
macro to ‘1’. Here is an simple example
of how to use consoleReadLine
.
int main (int argc, char **argv) String new s; String new promptStr; if (argc > 1) promptStr = argv[1]; else promptStr = "Prompt "; printf ("Readline test. Type ^C or, \"quit,\" to exit.\n"); #if HAVE_GNU_READLINE printf ("Ctalk built with GNU Readline Support.\n"); #else printf ("Ctalk built without GNU Readline Support.\n"); #endif while (1) s consoleReadLine promptStr; printf ("You typed (or recalled), \"%s.\"\n", s); /* * Matches both, "quit," and, "quit\n." */ if (s match "quit") break; } }
Next: Self and super, Previous: Basic classes, Up: Top [Index]