5.1.1. Stream File Operations

Mezi nejjednodušší operace patří sekvenční přístup k souborům po záznamech nebo po bajtech, následují operace pro náhodný přístup. Téměř vždy mají podobu pětice operací pro otevření a zavření souboru, nastavení pozice v souboru, čtení a zápis.

Těmto operacím v podstatě odpovídá dnešní představa souboru jako streamu bajtů, případně někdy více streamů bajtů. Výjimkami jsou specializované systémy souborů, které dovolují vnitřní členění souborů například v podobě stromu, ale ty jsou spíše z urban legends.

Za úvahu stojí, proč jsou operace na soubory typicky rozděleny právě do zmiňované pětice. Je totiž zjevně možné udělat jen operace read a write, které budou specifikovat jméno souboru, pozici a velikost bloku.

Důvody pro pětici operací jsou možnost odstranit při běžném způsobu práce se soubory opakování operací jako je nalezení pozice na disku ze jména souboru a pozice v souboru, možnost spojit otevírání souboru s dalšími operacemi jako je zamykání nebo kontrola oprávnění.

Důvodem pro dvojici operací je možnost implementovat file systém bezestavově, což přináší výhody v distribuovaných systémech.

Operace bývají k dispozici v synchronní i asynchronní verzi.

5.1.1.1. Example: Linux Stream File Operations

int open (char *pathname, int flags);
int open (char *pathname, int flags, mode_t mode);
int creat (char *pathname, mode_t mode);
int close (int fd);

The open, creat and close operations open and close a file stream. The O_RDONLY, O_WRONLY, O_RDWR open mode flags tell whether the file is opened for reading, writing, or both. This information is useful for access right checks and potentially also for sharing and caching support. These flags can be combined with O_CREAT to create the file if needed, O_EXCL to always create the file, O_TRUNC to truncate the file if applicable, O_APPEND to append to the file.

The O_NONBLOCK flag indicates that operations on the file stream should not block, O_SYNC requests that operations that change the file stream block until the changes are safely written to the underlying media.

The value of mode contains the standard UNIX access rights.

off_t lseek (int fildes, off_t offset, int whence);

The lseek operation sets the position in the file stream. The whence argument is one of SEEK_SET, SEEK_CUR, SEEK_END, indicating whether the offset argument is counted relatively from the beginning, current position, or end of the file stream.

ssize_t read (int fd, void *buf, size_t count);
ssize_t write (int fd, void *buf, size_t count);
ssize_t pread (int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite (int fd, void *buf, size_t count, off_t offset);

The read and write operations are trivial, more interesting are their vectorized and asynchronous counterparts.

ssize_t readv (int fd, struct iovec *vector, int count);
ssize_t writev (int fd, struct iovec *vector, int count);

struct iovec {
  void    *iov_base;
  size_t  iov_len;
};

int aio_read (struct aiocb *aiocbp);
int aio_write (struct aiocb *aiocbp);

int aio_error (struct aiocb *aiocbp);
ssize_t aio_return (struct aiocb *aiocbp);

int aio_suspend (
  struct aiocb *cblist [],
  int n, struct timespec *timeout);

int aio_cancel (int fd, struct aiocb *aiocbp);

int lio_listio (
  int mode, struct aiocb *list [],
  int nent, struct sigevent *sig);

struct aiocb {
  int              aio_fildes;
  off_t            aio_offset;
  void             *aio_buf;
  size_t           aio_nbytes;
  int              aio_reqprio;
  struct sigevent  aio_sigevent;
  int              aio_lio_opcode;
  ...
}
int posix_fadvise (int fd, off_t offset, off_t len, int advice);
int posix_fallocate (int fd, off_t offset, off_t len);

Advice can be given on future use of the file. Flags describing the future use include POSIX_FADV_NORMAL for no predictable pattern, POSIX_FADV_SEQUENTIAL and POSIX_FADV_RANDOM for specific patterns, POSIX_FADV_NOREUSE for data accessed once, and POSIX_FADV_WILLNEED and POSIX_FADV_DONTNEED to determine whether data will be accessed in the near future.