Node:Writing files at a low level, Next:, Previous:Reading files at a low level, Up:Low-level file routines



Writing files at a low level

You can write a block of information to a file with the write function, which is called by all high-level file writing routines, such as fwrite. It takes three parameters. The first is the file descriptor of the file you wish to write to. The second is a buffer, of type void *, that contains the data you wish to write. (It can be an array of bytes, but need not be a text string. Null characters in the data are treated in the same way as other characters.) The third parameter is of type size_t, and specifies the number of bytes that are to be written.

The return value of this function is of type ssize_t, and indicates the number of bytes actually written. This may be the same as the third parameter (the number of bytes to be written), but may be less; you should always call write in a loop, and iterate the loop until all data has been written. If there is an error, write returns -1. The write function will return the following error codes in the system variable errno, as well as the usual file name errors. (See Usual file name errors.)


EBADF
The file descriptor specified is invalid, or is not open for writing.
EFBIG
If the data were written, the file written to would become too large.
EIO
There has been a hardware error.
EINTR
The write operation was temporarily interrupted.
ENOSPC
The device containing the file is full.

In addition to the error codes above, write can return some error codes that are mainly of interest to advanced C programmers. If write fails, you should check errno to see if the error was EINTR; if it was, you should repeat the write call each time.

Even though low-level file routines do not use buffering, and once you call write, your data can be read from the file immediately, it may take up to a minute before your data is physically written to disk. You can call the fsync routine (see below) to ensure that all data is written to the file; this usage is roughly analogous to the high-level file routine fflush.

The fsync routine takes a single parameter, the file descriptor to synchronise. It does not return a value until all data has been written. If no error occurred, it returns a 0; otherwise, it returns -1 and sets the system variable errno to one of the following values:


EBADF
The file descriptor specified is invalid.
EINVAL
No synchronization is possible because the system does not implement it.

Here is a code example that demonstrates the use of the write, read, and fsync functions. (See Reading files at a low level, for more information on read.)

#include <stdio.h>
#include <fcntl.h>

int main()
{
  char my_write_str[] = "1234567890";
  char my_read_str[100];
  char my_filename[] = "snazzyjazz.txt";
  int my_file_descriptor, close_err;

  /* Open the file.  Clobber it if it exists. */
  my_file_descriptor = open (my_filename, O_RDWR | O_CREAT | O_TRUNC);

  /* Write 10 bytes of data and make sure it's written */
  write (my_file_descriptor, (void *) my_write_str, 10);
  fsync (my_file_descriptor);

  /* Seek the beginning of the file */
  lseek (my_file_descriptor, 0, SEEK_SET);

  /* Read 10 bytes of data */
  read (my_file_descriptor, (void *) my_read_str, 10);

  /* Terminate the data we've read with a null character */
  my_read_str[10] = '\0';

  printf ("String read = %s.\n", my_read_str);

  close (my_file_descriptor);

  return 0;
}