系统调用之文件操作详解


系统调用概述及文件操作

在计算机系统中,系统调用是用户程序向操作系统请求服务的重要机制。本文将概述系统调用及其相关概念,包括内核态与用户态、库函数与系统调用的关系,以及文件操作的相关函数。

内核态与用户态

在大多数现代操作系统中,处理器的操作等级被划分为不同的权限级别。以 Intel CPU 为例,其权限分为四个级别,即 Ring 0、Ring 1、Ring 2 和 Ring 3。其中,Ring 0 为最高权限,Ring 3 为最低权限。Linux 系统采用的则是 Ring 0 和 Ring 3,其中:

  • 内核态 (Ring 0): 在这一模式下,程序可以直接访问硬件资源和系统内核。这种模式下的线程被称为内核线程。
  • 用户态 (Ring 3): 在该模式下,程序被限制无法直接访问硬件资源,所有请求必须通过系统调用转交给内核处理。这种模式下的线程称为用户线程。

内核态与用户态之间的切换是通过上下文切换来实现的,频繁的切换会导致程序执行效率降低。

库函数与系统调用的关系

在 C 语言编程中,有些库函数会调用系统调用,有些则不会。系统调用是操作系统提供的接口,用于执行特权操作,而库函数则是对系统调用的一个封装,提供了更高级或更便捷的功能。例如,printf 函数是一个库函数,它最终会调用系统调用来输出数据。

文件操作

文件操作是使用系统调用的一个重要方面。以下介绍常用的文件操作系统调用。

int open(char *path, int flag);

int open(char *path, int flag, int mode);

参数:

  • path: 要打开的文件路径。
  • flag: 文件打开的状态:
    • O_RDONLY: 只读模式。
    • O_WRONLY: 只写模式。
    • O_RDWR: 读写模式。
    • O_CREAT: 如果文件不存在,则创建新文件。
    • O_APPEND: 以追加模式打开文件。
    • O_NONBLOCK: 非阻塞模式。

多个状态之间可以使用 | 连接。

  • mode: 文件权限(仅当使用三参数形式时有效):
    • 0: 不可读,不可写,不可执行。
    • 1: 可执行。
    • 2: 可写。
    • 4: 可执行且可写。

示例代码:

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

int main() {
    int fd = open("example.txt", O_CREAT | O_WRONLY | O_APPEND, 0644);
    if (fd < 0) {
        perror("Failed to open file");
        exit(EXIT_FAILURE);
    }
    // 文件成功打开,接下来可以进行写入操作
    close(fd);
    return 0;
}

int close(int fd)

用于关闭打开的文件。

示例代码:

if (close(fd) < 0) {
    perror("Failed to close file");
}

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

用于向打开的文件中写入数据。

示例代码:

const char *text = "Hello, World!\n";
if (write(fd, text, strlen(text)) < 0) {
    perror("Failed to write to file");
}

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

用于从打开的文件中读取数据。

示例代码:

char buffer[100];
ssize_t bytesRead = read(fd, buffer, sizeof(buffer) - 1);
if (bytesRead < 0) {
    perror("Failed to read from file");
} else {
    buffer[bytesRead] = '\0'; // 确保字符串以 null 结尾
    printf("Read from file: %s", buffer);
}

int fcntl(int fd, int cmd, int arg)

用于操作文件描述符的状态。

参数:

  • fd: 文件描述符。
  • cmd: 操作方式:
    • F_DUPFD: 拷贝已有文件描述符。
    • F_GETFL: 获取文件状态。
    • F_SETFL: 设置文件状态。
  • arg: 操作方式的值。

示例代码:

int flags = fcntl(fd, F_GETFL);
if (flags < 0) {
    perror("Failed to get file status flags");
} else {
    // 设置文件为非阻塞模式
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

int stat(const char *path, struct stat *buf);

参数:

  • path: 文件路径。
  • buf: 存储文件状态的结构体变量指针。

示例代码:

struct stat fileInfo;
if (stat("example.txt", &fileInfo) < 0) {
    perror("Failed to get file status");
} else {
    printf("File size: %lld bytes\n", (long long)fileInfo.st_size);
}

文件描述符

文件描述符是系统打开文件时为文件分配的标识符。通常情况下,系统默认打开三个文件:标准输入、标准输出和错误输出,分别对应:

  • 标准输入: 0
  • 标准输出: 1
  • 错误输出: 2

实用经验(注意)

  • 如果文件存在,建议使用两参数形式的 open 函数。
  • 如果文件不存在,建议使用三参数形式的 open 函数。

文件夹操作

文件夹操作的基本系统调用包括:

  • DIR *opendir(const char *name): 打开目录。
  • int closedir(DIR *dirp): 关闭目录。
  • struct dirent *readdir(DIR *dirp): 读取目录中的文件。

示例代码:

#include <dirent.h>

DIR *dir = opendir(".");
if (dir == NULL) {
    perror("Failed to open directory");
    exit(EXIT_FAILURE);
}

struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
    printf("Found file: %s\n", entry->d_name);
}

closedir(dir);

代码示例

实现某一目录下的所有文件及文件夹的遍历

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
// 遍历家目录下的文件夹
void bianLi(char *name)
{
    // 打开家目录
    DIR *home = opendir(name);
    if (home == NULL)
    {
        printf("目录打开失败");
        return 0;
    }
    while (1)
    {
        struct dirent *res = readdir(home);
        // 遍历完毕,跳出循环
        if (res == NULL)
        {
            break;
        }
        // 如果为目录
        if (res->d_type == DT_DIR)
        {
            if (strcmp(res->d_name, ".") == 0 || strcmp(res->d_name, "..") == 0)
            {
                continue;
            }
            char names[300] = {0};
            strcat(names, name);
            strcat(names, "/");
            strcat(names, res->d_name);
            // 回调函数
            printf("%s\n", names);
            bianLi(names);
        }
        // 如果为文件
        else if (res->d_type == DT_REG)
        {
            printf("%s\n", res->d_name);
        }
    }
    closedir(home);
}
//这是主函数
int main(int argc, char const *argv[])
{
	//家目录是"/home/wyf"
    char *name = "/home/wyf";
    bianLi(name);
    return 0;
}

实现某一文件类容的复制

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
// stat
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
// 空间
#include <stdlib.h>
// 文件类容的复制
int main(int argc, char const *argv[])
{
	//这个是我已经存在的文件
    int temp = open("/home/wyf/2024/3jieDuan/02day/test.txt",O_RDONLY);
    if (temp == -1)
    {
        printf("打开失败!\n");
        return 0;
    }
    //下面这里选择的模式是:O_WRONLY | O_APPEND | O_CREAT 写入,尾部追加,没有就创建该文件
    //上面文章提到过(经验)
    //如果文件存在,建议使用两参数形式的 open 函数。
	//如果文件不存在,建议使用三参数形式的 open 函数。
    int temp2 = open("/home/wyf/2024/3jieDuan/02day/testCpy.txt",O_WRONLY | O_APPEND | O_CREAT,0664);
    if (temp2 == -1)
    {
        printf("创建失败\n");
        return 0;
    }
    // 定义存储信息的结构体,并将信息存储在tes里面
    struct stat tes;
    stat("/home/wyf/2024/3jieDuan/02day/test.txt",&tes);
    int len = tes.st_size;
    // printf("长度为:%d\n",len);
    char *res = (char *)calloc(len+1,1);
    read(temp,res,len);
    write(temp2,res,len);
    return 0;
}

实现从键盘录入文件地址,判断该文件是文件夹还是文件,并显示器可操作权限

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
// 从键盘录入文件地址,判断该文件是文件夹还是文件,并显示器可操作权限
int main(int argc, char const *argv[])
{
    char name[100] = {0};
    read(0, name, 100);
    int len = strlen(name);
    //最后一位换行置为0
    name[len-1] = 0;
    //系统stat结构体
    struct stat res;
    int temp = stat(name, &res);
    if (temp == -1)
    {
        printf("录入的%s不存在\n", name);
        return;
    }
    else
    {
    	//这里只展示了一种类型的判断
        if ((res.st_mode & __S_IFREG) == __S_IFREG)
        {
            printf("%s是文件\t", name);
        }
        else
        {
            printf("%s是目录\t", name);
        }
        // 
        if ((res.st_mode & S_IRUSR) == S_IRUSR)
        {
            printf("可以读取\t");
        }
        else
        {
            printf("不可读取\t");
        }
        // 
        if ((res.st_mode & S_IWGRP) == S_IWGRP)
        {
            printf("可以写\t");
        }
        else
        {
            printf("不可以写\t");
        }
        // 
        if ((res.st_mode & S_IXUSR) == S_IXUSR)
        {
            printf("可以执行\n");
        }
        else
        {
            printf("不可执行\n");
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值