Unix C Programming - file i/o



1. open()/creat()/close()

#include <fcntl.h>
int creat (const char *filename, mode_t mode)
int open (const char *filename, int flags)
int open (const char *filename, int flags[, mode_t mode])
                                            - 成功返回:fd;失败返回:-1
int close (int filedes)
                                            - 成功返回:0;失败返回:-1

The open() function creates and returns a new file descriptor for the file named by filename. Initially, the file position indicator for the file is at the beginning of the file.

The flags argument controls how the file is to be opened. This is a bit mask; you create the value by the bitwise OR of the appropriate parameters (using the ‘|’ operator in C). See File Status Flags, for the parameters available.

File Status Flags:

O_RDONLY => 只读打开
O_WRONLY => 只写打开
O_RDWR => 读写打开
O_EXEC => 执行打开
O_APPEND => 追加打开,且线程安全
O_CREAT => 若文件不存在,创建文件,需要添加第三项参数描述文件权限
O_EXEC => 如果使用了O_CREAT而且文件已经存在,就会发生一个错误
O_NOBLOCK => 以非阻塞的方式打开一个文件
O_TRUNC => 如果文件已经存在,则删除文件的内容
O_SYNC => write等待写入完成后才返回

If added O_CREAT then open() = creat(), the argument mode (see Permission Bits) is used only when a file is created, but it doesn’t hurt to supply the argument in any case.

Permission Bits:

S_IRUSR => 用户可以读
S_IWUSR => 用户可以写
S_IXUSR => 用户可以执行
S_IRWXU => 用户可以读、写、执行
S_IRGRP => 组可以读
S_IWGRP => 组可以写
S_IXGRP => 组可以执行
S_IRWXG => 组可以读写执行
S_IROTH => 其他人可以读
S_IWOTH => 其他人可以写
S_IXOTH => 其他人可以执行
S_IRWXO => 其他人可以读、写、执行
S_ISUID => 设置用户执行ID
S_ISGID => 设置组的执行ID


ssize_t read (int filedes, void *buffer, size_t size)
ssize_t pread (int filedes, void *buffer, size_t size, off_t offset)
                                            - 成功返回:读取byte数;失败返回:-1

The read() function reads up to size bytes from the file with descriptor filedes, storing the results in the buffer.The return value is de number of bytes actually read. The number might actually smaller than size, for the sake of not enough bytes left or if there aren’t that many bytes immediately available. But if return value is -1, then error happens.

The pread() function not read from the current file descriptor filedes, but read from offset of file begin.


ssize_t write (int filedes, const void *buffer, size_t size)
ssize_t pwrite (int filedes, const void *buffer, size_t size, off_t offset)
                                            - 成功返回:写入byte数;失败返回:-1

Ok, write()/pwrite() is the same as read.

We can write an example to copy file like linux command, example here: (Usage: ./a.out frompath topath)

#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#define BUFFSIZE 1024
int main(int argc, char** argv) {
    if (argc != 3) {
        printf("Usage: ./a.out frompath topath\n");
    char buff[BUFFSIZE];
    int fd1, fd2, read_byte, write_byte;
    if ((fd1 = open(argv[1], O_RDONLY)) < 0) {
        printf("%s: open file error\n", argv[1]);
    if ((fd2 = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
        printf("%s: create file error", argv[2]);
    while ((read_byte = read(fd1, buff, BUFFSIZE)) != 0) {
        if (read_byte == -1 && (errno != EINTR)) {
            printf("%s: read buff error\n", argv[1]);
        } else if (read_byte > 0) {
            write_byte = write(fd2, buff, read_byte);
            if (write_byte == -1) {
                printf("%s: write buff error\n", argv[2]);
    return 0;

➜ $: gcc cp.c
➜ $: echo “1234567890” > test1
➜ $: ./a.out test1 test2
➜ $: ll test*

-rw-r--r--  1 homeway  staff    11B Mar  2 21:48 test1
-rw-------  1 homeway  staff    11B Mar  2 21:48 test2

error see here: http://homeway.me/2017/03/02/apue-file-io/#error


off_t lseek(int fd, off_t offset, int whence)
                                            - 成功返回:偏移量;失败返回:-1

Every open file has a current file offset, always is a positive. lseek() can change current file offset, offset can be positive or negetive, whence followed here:

SEEK_SET => offset begin from index = 0
SEEK_CUR => offset begin from current point, offset can be positive or negetive
SEEK_END => add file size, offset can be positive or negetive

If offset if bigger than file size, we can create a file hole, example here:

#include <fcntl.h>
#include <stdio.h>
int main(int argc, char** argv) {
    if (argc == 1) {
        printf("Usage: %s pathname", argv[0]);
    int fd;
    if ((fd = creat(argv[1], FILE_MODE)) < 0) {
        err_sys("create file %s error", argv[1]);
    char buff1[11] = {"1234567890"};
    char buff2[11] = {"abcdefghij"};
    if (write(fd, buff1, 10) != 10) {
        err_sys("write %s error", argv[1]);
    if (lseek(fd, 1024, SEEK_SET) < 0) {
        err_sys("lseek %s error", argv[1]);
    if (write(fd, buff2, 10) != 10) {
        err_sys("write %s error", argv[1]);
    char cmd[1024];
    sprintf(cmd, "od -c %s", argv[1]);
    return 0;

➜ $: gcc lseek.c
➜ $: ./a.out

0000000    1   2   3   4   5   6   7   8   9   0  \0  \0  \0  \0  \0  \0
0000020   \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0002000    a   b   c   d   e   f   g   h   i   j


File error is defined in :

    The process does not have search permission for a directory component of the file name.

    This error is used when either the total length of a file name is greater than PATH_MAX, or when an individual file name component has a length greater than NAME_MAX. See Limits for Files.

    This error is reported when a file referenced as a directory component in the file name doesn’t exist, or when a component is a symbolic link whose target file does not exist. See Symbolic Links.

    A file that is referenced as a directory component in the file name exists, but it isn’t a directory.

    Too many symbolic links were resolved while trying to look up the file name. The system has an arbitrary limit on the number of symbolic links that may be resolved in looking up a single file name, as a primitive way to detect loops. See Symbolic Links.


本文出自 夏日小草,转载请注明出处:http://homeway.me/2017/03/02/apue-file-io/

-by grasses

2017-03-02 21:52:34

Fork me on GitHub