Input From Files (read())#

#include <fcntl.h>
int open(const char *pathname, int flags);
#include <unistd.h>
ssize_t read(int fd, void buf[.count], size_t count);

open() File For Reading#

  • Simplest case

  • Only flags needed: O_RDONLY (or O_RDWR if writing is also intended)

  • Third parameter (mode) ignored

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

int main()
{
    int fd = open("/etc/passwd", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }
    // ... do something with fd ...
    close(fd);
    return 0;
}

Read Block Of Bytes#

  • Read first 16 bytes of file

  • Write them to standard output, just to do something meaningful with what we just read

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

int main()
{
    int fd = open("/etc/passwd", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }
    
    char bytes[16];
    ssize_t nbytes_read = read(fd, bytes, 16);         // <-- at most 16 into bytes[]
    if (nbytes_read == -1) {
        perror("read");
        return 1;
    }

    ssize_t nbytes_written = write(STDOUT_FILENO,      // <-- just to see them somewhere
                                   bytes, nbytes_read);
    if (nbytes_written == -1) {
        perror("write");
        return 1;
    }
    
    close(fd);
    return 0;
}
$ strace ./sysprog-fileio-read-one-block
...
openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3
read(3, "root:x:0:0:Super", 16)         = 16
write(1, "root:x:0:0:Super", 16root:x:0:0:Super)        = 16
close(3)                                = 0
...

Read Until End-Of-File#

  • End-of-file: there won’t be any input anymore (file is exhausted)

  • Reached when read() returns 0 bytes

  • ⟶ usually used to end some loop

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

int main()
{
    int fd = open("/etc/passwd", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    while (true) {
        char bytes[16];
        ssize_t nbytes_read = read(fd, bytes, 16);
        if (nbytes_read == -1) {
            perror("read");
            return 1;
        }
        if (nbytes_read == 0)                          // <-- end-of-file
            break;

        ssize_t nbytes_written = write(STDOUT_FILENO, bytes, nbytes_read);
        if (nbytes_written == -1) {
            perror("write");
            return 1;
        }
    }
    
    close(fd);
    return 0;
}

Questions#

  • How does read() know where a previous read() left off?

    See File Descriptors: Basics

    ../../../../../../../_images/file-descriptor.svg
  • Error conditions. Modify program to open argv[1] and …

    • Show “permission denied” (EACCESS)

    • Show “does not exist” (EEXIST)