Add Book to My BookshelfPurchase This Book Online

Chapter 3 - Low-Level I/O Routines

UNIX Systems Programming for SVR4
David A. Curry
 Copyright © 1996 O'Reilly & Associates, Inc.

Input and Output
To move data between a file and your program, use the read and write functions:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
ssize_t write(int fd, const void *buf, size_t nbytes);
The read function transfers up to nbytes bytes from the file referenced by fd and stores them in the area of memory pointed to by buf. The number of bytes actually read is returned. If 0 is returned, this indicates that end-of-file is reached and there is no data left to read. The write function transfers up to nbytes bytes of data from the area of memory pointed to by buf to the file referenced by fd. The number of bytes actually written is returned. Both routines return -1 if an error occurs and store an error code in the external variable errno.
Unlike languages in which the I/O instructions are built into the language, read and write do not perform any formatting or data conversion. Although you can pass a pointer to any C data type to both functions, you are working with the actual contents of memory, not the human-readable form of those contents. For example, the following program writes 12 bytes (4 bytes for each integer) to the standard output:
main()
{
     int n;
     for (n = 1; n <= 3; n++)
         write(1, &n, sizeof(int));
}
Here is the standard output:
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010
00000000 00000000 00000000 00000011
Contrast this with the PASCAL program:
program x;
     var n : integer;
begin
     for n := 1 to 3 do begin
         writeln(n);
     end
end.
or the FORTRAN program:
     integer n
     do 10 n = 1,3
         print *, n
10  continue
     stop
     end
Both the PASCAL and FORTRAN programs print out the ASCII representations of the number n:
1
2
3
To accomplish the same thing with write, you need to convert the integer n to a character string and then write it out:
int n;
char buf[32];
intToString(n, buf);
write(1, buf, strlen(buf));
Similarly, if you use the read function to read in a number, you must enter four bytes containing the appropriate binary bits to give you a number of the appropriate value:
int n;
read(0, &n, sizeof(int));
Instead, if what you want is for the user to enter a number (say, 123) and have that value stored in n, you need code like this:
int i, n;
char buf[32];
i = read(0, buf, sizeof(buf));
buf[i] = '\0';
n = atoi(buf);
Note that because read does not automatically null-terminate the data it reads in, the program must do this explicitly.
Example 3-1 shows a program that takes two filenames as arguments. It opens the first file for reading and the second file for writing and then appends the contents of the first file to the second file.
Example 3-1:  append
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int
main(int argc, char **argv)
{
    int n, in, out;
    char buf[1024];
    if (argc != 3) {
        write(2, "Usage: append file1 file2\n", 26);
        exit(1);
    }
    /*
     * Open the first file for reading.
     */
    if ((in = open(argv[1], O_RDONLY)) < 0) {
        perror(argv[1]);
        exit(1);
    }
    /*
     * Open the second file for writing.
     */
    if ((out = open(argv[2], O_WRONLY | O_APPEND)) < 0) {
        perror(argv[2]);
        exit(1);
    }
    /*
     * Copy data from the first file to the second.
     */
    while ((n = read(in, buf, sizeof(buf))) > 0)
        write(out, buf, n);
    close(out);
    close(in);
    exit(0);
}
     % cat a
     file a line one
     file a line two
     file a line three
     % cat b
     file b line one
     file b line two
     file b line three
     % append a b
     % cat b
     file b line one
     file b line two
     file b line three
     file a line one
     file a line two
     file a line three
Note the calls to read and write: when calling read, we pass the size of the buffer buf, but when calling write, we pass the number of bytes read, n. If we were to pass the size of the buffer instead, then we would end up writing out some number of correct bytes (the ones we read) and a large number of “garbage” bytes.
Two other functions for reading and writing, readv and writev, were introduced in BSD UNIX and are also present in SVR4. These functions allow a program to perform “scatter-gather” I/O, by passing in the addresses of several buffers in one call. Because these functions are rarely used and are not very portable anyway, this book will not discuss them further.

Previous SectionNext Section
Books24x7.com, Inc © 2000 –  Feedback