一、文件操作方法

linux中有两种方法可以操作文件:系统调用和c库函数。

1. 什么是系统调用?

由操作系统实现并提供给外部应用程序的编程接口(API),是应用程序同系统之间数据交互的桥梁。

C标准函数和系统函数调用关系,如图:
Linux系统编程 | 01 -文件操作_#include

2. c库函数

待写。

二、文件IO(系统调用API)

库函数头文件统一使用头文件unistd.h

1. open创建

头文件:

#include <fcntl.h>

函数原型:

int open(const char *pathname, int flags);

参数说明:

  • pathname:文件名
  • flag:文件打开标志
flag参数 说明
O_RDONLY 只读方式打开
O_WRONLY 只写方式打开
O_RDWR 可读可写
O_CREAT 文件不存在则创建(文件权限由mode参数指定)
O_APPEND 追加方式写入
O_EXCL 判断文件是否存在
O_TRUNC 截断文件大小为0/清空文件
O_NONBLOCK

mode权限参数说明:

  1. 该参数使用八进制指定;
  2. 该参数受umask(默认0002)影响:最终权限 = mode &~ umask,其实就是把我们所指定权限中other用户的写权限给去除。

返回值说明:

  • 成功返回fd号
  • 失败返回-1,错误原因errno给出

2. close关闭

头文件:

#include <unistd.h>

函数原型:

int close(int fd);

参数说明:

  • fd:文件描述符

3. write写入

头文件:

#include <unistd.h>

函数原型:

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

参数说明:

  • fd:文件描述符
  • buf:待写数据指针
  • count:待写数据大小

返回值:

  • 成功:返回写入的字节数
  • 失败:返回-1,error被设置

4. read读取

头文件:

#include <unistd.h>

函数原型:

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

参数说明:

  • fd:文件描述符
  • buf:缓冲区指针
  • count:要读取的数据大小

返回值:

  • 成功:返回读取的字节数
  • 失败:返回-1,error被设置

说明:

在支持查找的文件上,读取操作从文件偏移量开始,并且文件偏移量会随着读取递增。如果文件偏移量在文件末尾或者超过文件末尾,则返回0

5. lseek文件偏移

头文件:

#include <unistd.h>

函数原型:

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

参数说明:

  • fd:文件描述符
  • offset:偏移量
  • count:要读取的数据大小
    • SEEK_SET:The file offset is set to offset bytes.
    • SEEK_CUR:The file offset is set to its current location plus offset bytes.
    • SEEK_END:The file offset is set to the size of the file plus offset bytes.

返回值:

  • 成功:返回当前所在偏移量
  • 失败:返回-1,error被设置
三、测试程序

demo1——默认创建文件的权限

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

int main(int argc, char *argv[])
{
    int fd;

    fd = open("hello.txt", O_RDWR | O_CREAT);

    printf("fd is %d\n", fd);

    close(fd);

    return 0;
}

执行结果:

fd is 3

如果hello.txt不存在,则open会创建该文件,但我们并没有指定文件权限(mode),查看默认创建文件的权限:

---Srwx--T 1 ubuntu ubuntu    0 Sep  5 16:40 hello.txt

后续文件权限分析?

demo2——指定创建文件的权限

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

int main(int argc, char *argv[])
{
    int fd;

    // 0644: rw-r--r--
    fd = open("hello.txt", O_RDWR | O_CREAT, 0644);

    printf("fd is %d\n", fd);

    close(fd);

    return 0;
}

执行之后再次查看hello.txt的权限:

rw-r--r-- 1 ubuntu ubuntu    0 Sep  5 16:47 hello.txt

demo3——指定创建文件的权限受umask影响

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

int main(int argc, char *argv[])
{
    int fd;

    // 0777: rwxrwxrwx
    // umask: 0002
    fd = open("hello.txt", O_RDWR | O_CREAT, 0777);

    printf("fd is %d\n", fd);

    close(fd);

    return 0;
}

创建出的hello.txt权限为:

-rwxrwxr-x 1 ubuntu ubuntu    0 Sep  5 17:03 hello.txt*

demo4-打开文件出错

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

int main(int argc, char *argv[])
{
    int fd;

    fd = open("hello.txt", O_RDWR);

    printf("fd is %d\n", fd);
    printf("errno is %d(%s)\n", errno, strerror(errno));

    close(fd);

    return 0;
}

当hello.txt不存在时,日志为:

fd is -1
errno is 2(No such file or directory)

demo5——文件偏移量导致读取失败

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

int main(int argc, char *argv[])
{
    int fd;
    int nbytes;
    char write_buf[] = "helloworld!";
    char read_buf[1024] = {0};

    /* 1. open file */
    fd = open("hello.txt", O_RDWR | O_CREAT, 0664);
    if (fd < 0) {
        printf("open fail, fd is %d\n", fd);
        printf("errno is %d(%s)\n", errno, strerror(errno));
        return -1;
    }

    /* 2. write */
    nbytes = write(fd, write_buf, sizeof(write_buf));
    if (nbytes < 0) {
        printf("write fail, errno is %d(%s)\r\n", errno, strerror(errno));
        return -1;
    }
    printf("write %d bytes\r\n", nbytes);

    /* 3. read */
    nbytes = read(fd, read_buf, sizeof(read_buf));
    if (nbytes < 0) {
        printf("read fail, errno is %d(%s)\r\n", errno, strerror(errno));
        return -1;
    }
    printf("read %d bytes:[%s]\r\n", nbytes, read_buf);

    /* 4. close */
    close(fd);

    return 0;
}

write写入完成后,文件偏移量在文件末尾,直接读取导致返回0:

write 12 bytes
read 0 bytes:[]

这个时候在read之前,使用lseek函数将文件偏移量恢复到文件开始处即可:

lseek(fd, 0, SEEK_SET);