Unix low-level file operations
The stdio library has a high-level interface to the file operations, with printf,
putchar, etc. These are built from a lower-level interface. Typical calls from
this are
#include
#include
#include
int creat(char *path,
mode_t mode);
int open(char *path,
int oflag,
...);
int close(int fildes);
int read(int fildes,
char *buf,
unsigned nbyte);
int write(int fildes,
char *buf,
unsigned nbyte);
int chmod(char *path,
mode_t mode);
int stat(char *path,
struct stat *buf);
creat takes the pathname of a file and creates a new file, removing the contents
if it already existed. The mode sets the access permissions. This is a bit-wise
OR of the file permissions:
S_IRUSR 0400
S_IWUSR 0200
S_IXUSR 0100
S_IRGRP 040
S_IWGRP 020
S_IXGRP 010
S_IROTH 04
S_IWOTH 02
S_IXOTH 01
This follows the rwx for user, group and other that is shown by ``ls -l''.
The open call opens the file in the mode given by oflag, and returns a file
descriptor. This is an integer which the O/S uses to index into a per process
file descriptor table, which is used to keep info about open files. Zero is
always stdin, 1 is stdout, 2 is stderr.
oflag is a bit-wise OR of a number of constants
O_RDONLY
O_WRONLY
O_CREAT
O_TRUNC
When O_CREAT is one of these flags, an additional argument to open is the file
permission mode.
The read call is a block read of a given number of bytes. This could be tuned
to the physical characteristics of the device read from, for example.
For example, it may be much faster to do a block read of 1024 bytes from
a hard disk than to do 1024 reads of 1 byte from the disk.
The value returned is the actual number of bytes read.
This may be less than the number asked for. For example
-
if you ask for
1024 bytes to be read from a file that only has 53 bytes in it, you will
only get 53.
- input from the keyboard is normally
line-buffered, so no matter how many you ask for, you will only get a
line at a time.
-
a pipeline is often implemented with a buffer size of 4k. Reads
of more than that may cause the pipeline buffer to be filled and emptied
several times.
``read'' returns zero on EOF, and -1 on error. A while loop to read using
this call should always test the return value for > 0:
while ((nread = read(...)) > 0)
...
if (nread == 0)
/* EOF code */
else
/* error code */
The write call is also a block write of a number of bytes. It returns -1 if
a write error occurs (such as no space left).
Example
This is a simple version of cp, using the low-level I/O.
#include
#include
#include
#include
#define SIZE 1024
#define MODE (S_IRUSR | S_IWUSR | \
S_IRGRP | S_IROTH)
int main(int argc,
char *argv[])
{
int src, dst;
int in_count, out_count;
char buf[SIZE];
int nread;
if (argc != 3) {
fprintf(stderr,
"Usage: cp f1 f2
");
exit(1);
}
if ((src = open(argv[1],
O_RDONLY)) == -1) {
fprintf(stderr,
"Cant open %s
",
argv[1]);
exit(2);
}
if ((dst = creat(argv[2],
MODE)) == -1) {
fprintf(stderr,
"cant create %s
",
argv[2]);
exit(3);
}
while ((nread =
read(src, buf, SIZE))
> 0) {
if (write(dst, buf, nread)
== -1) {
fprintf(stderr,
"cant write
"),
exit(4);
}
}
exit(0);
}
When should you use these low-level functions? Only when you have to.
In general
use the high-level functions. There will be many times when we can't.
Note
that these functions are specific to the Unix API, and are not in Microsoft
C, for example. So code written using these functions will only be portable
across Unix, not to other Operating Systems.
Jan Newmarch
(http://pandonia.canberra.edu.au)
<jan@ise.canberra.edu.au>
Copyright © Jan Newmarch
Last modified: Wed Jun 18 20:53:05 1997