Posted on 2007-08-21 00:30
花之剑 阅读(291)
评论(0) 编辑 收藏
In the UNIX operating system, all input and output is done by reading or writing files, because
all peripheral devices, even keyboard and screen, are files in the file system. This means that a
single homogeneous interface handles all communication between a program and peripheral
devices.
In the most general case, before you read and write a file, you must inform the system of your
intent to do so, a process called opening the file. If you are going to write on a file it may also
be necessary to create it or to discard its previous contents. The system checks your right to do
so (Does the file exist? Do you have permission to access it?) and if all is well, returns to the
program a small non-negative integer called a file descriptor. Whenever input or output is to
be done on the file, the file descriptor is used instead of the name to identify the file. (A file
descriptor is analogous to the file pointer used by the standard library, or to the file handle of
MS-DOS.) All information about an open file is maintained by the system; the user program
refers to the file only by the file descriptor.
Since input and output involving keyboard and screen is so common, special arrangements
exist to make this convenient. When the command interpreter (the ``shell'') runs a program,
three files are open, with file descriptors 0, 1, and 2, called the standard input, the standard
output, and the standard error. If a program reads 0 and writes 1 and 2, it can do input and
output without worrying about opening files.
The user of a program can redirect I/O to and from files with < and >:
prog <infile >outfile
In this case, the shell changes the default assignments for the file descriptors 0 and 1 to the
named files. Normally file descriptor 2 remains attached to the screen, so error messages can
go there. Similar observations hold for input or output associated with a pipe. In all cases, the
file assignments are changed by the shell, not by the program. The program does not know
where its input comes from nor where its output goes, so long as it uses file 0 for input and 1
and 2 for output.
Low Level I/O - Read and Write
Input and output uses the read and write system calls, which are accessed from C programs
through two functions called read and write. For both, the first argument is a file descriptor.
The second argument is a character array in your program where the data is to go to or to
come from. The third argument is the number is the number of bytes to be transferred.
int n_read = read(int fd, char *buf, int n);
int n_written = write(int fd, char *buf, int n);
Each call returns a count of the number of bytes transferred. On reading, the number of bytes
returned may be less than the number requested. A return value of zero bytes implies end of
file, and -1 indicates an error of some sort. For writing, the return value is the number of bytes
written; an error has occurred if this isn't equal to the number requested.
Any number of bytes can be read or written in one call. The most common values are 1, which
means one character at a time (``unbuffered''), and a number like 1024 or 4096 that
corresponds to a physical block size on a peripheral device. Larger sizes will be more efficient
because fewer system calls will be made.
Putting these facts together, we can write a simple program to copy its input to its output, the
equivalent of the file copying program written for Chapter 1. This program will copy anything
to anything, since the input and output can be redirected to any file or device.
#include "syscalls.h"
main() /* copy input to output */
{
char buf[BUFSIZ];
int n;
while ((n = read(0, buf, BUFSIZ)) > 0)
write(1, buf, n);
return 0;
}
We have collected function prototypes for the system calls into a file called syscalls.h so we
can include it in the programs of this chapter. This name is not standard, however.
The parameter BUFSIZ is also defined in syscalls.h; its value is a good size for the local
system. If the file size is not a multiple of BUFSIZ, some read will return a smaller number of
bytes to be written by write; the next call to read after that will return zero.
#define BUFSIZ 1024
main()
{
char buf[BUFSIZ];
int n;
while((n=read(0,buf,BUFSIZ))>0)
write(1,buf,n);
}