File I/O: The universal I/O Model 

File I/O: The Universal I/O Model

Overview

Overview

/* Open a file */
fd = open(file_path, flags, mode);

/* Read a file */
num_byte_read = read(fd, buffer, sizeof(buffer));

/* Write a file */
num_byte_write = write(fd, buffer, sizeof(buffer));

/* Close a file */
close_st = close(fd);

Open

#include <sys/stat.h>
#include <fcntl.h>

int open(const char *paht, int flags, ... /* mode_t mode */);

/* Return file descriptor on success, or -1 on error. */

Open

File Access mode flags

File creation flags

Open file status flags

can be change by fcntl

cannot be change by fcntl

can be change by fcntl

Read

#include <unistd.h>

ssize_t read(int fd, void *buffer, size_t count);

/* Return number of bytes read, 0 on EOF, or -1 on error. */

Write

#include <unistd.h>

ssize_t write(int fd, void *buffer, size_t count);

/* Return number of bytes written, or -1 on error. */

Creat

#include <fcntl.h>

int creat(const char *paht, mode_t mode);

/* Return file descriptor, or -1 on error. */

Equivalent to

fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, mode);

Close

#include <unistd.h>

int close(int fd);

/* Return 0 on success, or -1 on error. */

lseek

#include <unistd.h>

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

/* Reutnr new file offset, or -1 on error. */

What kernel doing?

Kernel maintain a read-write offset (pointer)

lseek

File I/O: Further Detail 

File Control Operation - Fcntl

#include <fcntl.h>

int fcntl(int fd, int cmd, ... );

/* Return on success depend on command, or -1 on error. */

Relationship between fd and open files 

Duplicating  File Descriptor

# Redirection STDERR to STDOUT

$ ./SomeCommand 2>&1

How to do redirection in C?

#include <unistd.h>

int dup(int oldfd);

/* Return (new) file descriptor on success, or -1 on error. */

Duplicating  File Descriptor

/* close STDERR */
close(2);
/* dup STDOUT to newfd */
newfd = dup(1);
/* print something to STDOUT */
write(newfd, buffer, sizeof(buffer));

# Redirection STDERR to STDOUT

$ ./SomeCommand 2>&1

Equivalent to

Duplicating  File Descriptor

/* close STDERR */
close(2);
/* dup STDOUT to newfd */
newfd = dup(1);
/* print something to STDOUT */
write(newfd, buffer, sizeof(buffer));

/* combine close and dup */
dup2(1,2);
/* print something on STDOUT */
write(2, buffer, sizeof(buffer));

Equivalent to

File I/O at specified offset

#include <unistd.h>

ssize_t pread(int fd, void *buf, size_t count, off_t offset);
/* Return number of bytes read, 0 on EOF, -1 on error. */

ssize_t pwrite(int fd, void *buf, size_t count, off_t offset);
/* Return number of bytes read, -1 on error. */

Scatter-Gather I/O

Idea: Transfer multiple buffers of data in a single system call

scatter-input & gather-output

Scatter-Gather I/O

Scatter-Gather I/O

#include <sys/uio.h>

ssize_t readv(int fd, const struct iovec, int iovcnt);
/* Return number of bytes read, 0 on EOF, or -1 on error. */

ssize_t writev(int fd, const struct iovec, int iovcnt)
/* Return number of bytes write, or -1 on error. */
struct iovec {
    void *iov_base;
    size_t iov_len;
};

struct iovec define 

Atomicity and Race Conditions

if (-1 != (fd = open(argv[1], O_WRONLY))) {
    printf("[PID %ld] File \"%s\" already exists\n", (long)getpid(), argv[1]);
    close(fd);
} else {
    if (errno != ENOENT) {
        perror("Failed fo unexpected reason");
        exit(EXIT_FAILURE);
    } else {
        printf("[PID %ld] File \"%s\" doesn't exist yet\n", (long)getpid(), argv[1]);
        if (2 < argc) {
            sleep(6);
            printf("[PID %ld] Done sleeping\n",(long)getpid());
        }   
        if (-1 == (fd = open(argv[1], O_WRONLY | O_CREAT , S_IRUSR | S_IWUSR))) {
            perror("open");
            exit(EXIT_FAILURE);
        }   
        printf("[PID %ld] Create file \"%s\" exclusively\n", (long)getpid(), argv[1]);
    }   
}

Atomicity and Race Conditions

Atomicity and Race Conditions

How to solve this problem?

fd = open(argv[1], O_WRONLY | O_CREAT | O_EXCL, S_IRUSR|S_IWUSR)

Create Temporary File

#include <stdlib.h>

int mkstemp(char *template);
/* Return file descriptor on success, or -1 on error */
#include <stdio.h>

FILE *tmpfile(void);
/* Return file pointer on success, or NULL on error */

/dev/fd/n

n: file descriptors for the process

fd = open("dev/fd/1", O_WRONLY);
/* Equivalent to */
fd = dep(1);

See also /proc/[pid]/fd

Using in shell

$ ls | diff - oldfilelist
# Equivalent to
$ ls | /dev/fd/0 oldfilelist

How many file descriptor can be used?

# per process
$ ulimit -n

# system
cat /proc/sys/fs/file-max

File I/O VS. Buffering I/O

Why Buffering I/O usually has good performance?

The minimum unit of data which read from disk is block

Thanks for comming

Basic Concept about File I/O

By chang-ning tsai

Basic Concept about File I/O

  • 297