当前位置: 首页 > news >正文

系统调用之文件操作详解

文章目录

  • 系统调用概述及文件操作
    • 内核态与用户态
    • 库函数与系统调用的关系
    • 文件操作
      • `int open(char *path, int flag);`
      • `int open(char *path, int flag, int mode);`
      • `int close(int fd)`
      • `int write(int fd, const void *buf, size_t count)`
      • `int read(int fd, void *buf, size_t count)`
      • `int fcntl(int fd, int cmd, int arg)`
      • `int stat(const char *path, struct stat *buf);`
      • 文件描述符
      • 实用经验(注意)
      • 文件夹操作
  • 代码示例
    • 实现某一目录下的所有文件及文件夹的遍历
    • 实现某一文件类容的复制
    • 实现从键盘录入文件地址,判断该文件是文件夹还是文件,并显示器可操作权限


系统调用概述及文件操作

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

内核态与用户态

在大多数现代操作系统中,处理器的操作等级被划分为不同的权限级别。以 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: 可写。
    • 3: 可执行且可写。

示例代码:

#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);//最后一位换行置为0name[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;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【科研达人3个月搞定SCI论文:计算机视觉研究的实用计划】
  • 2024高教社杯数学建模国赛ABCDE题选题建议+初步分析
  • 【系统】Linux系统下载 Ubuntu/Debian/Deepin
  • python-Flask搭建简易登录界面
  • C#读取Excel的方法总结
  • Python函数的编写
  • Leetcode22括号生成(java实现)
  • 5个自动化测试用例设计的原则
  • 行为型设计模式-命令(command)模式-python实现
  • knime用三种方法提取列中需要的数据实战
  • ffmpeg音视频开发从入门到精通——ffmpeg下载编译与安装
  • php、Java、python房屋租赁系统 在线租房系统 房源出租平台(源码、调试、LW、开题、PPT)
  • 纵向合并单元格——table
  • Python爬虫入门篇!
  • 【QNX+Android虚拟化方案】101 - Android GVM 虚拟网络 Virt-Net 配置
  • 「译」Node.js Streams 基础
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • AngularJS指令开发(1)——参数详解
  • CentOS 7 修改主机名
  • css的样式优先级
  • Java-详解HashMap
  • Laravel 实践之路: 数据库迁移与数据填充
  • node学习系列之简单文件上传
  • Promise面试题2实现异步串行执行
  • Puppeteer:浏览器控制器
  • Redis学习笔记 - pipline(流水线、管道)
  • spring学习第二天
  • 第2章 网络文档
  • 对象引论
  • 那些被忽略的 JavaScript 数组方法细节
  • 驱动程序原理
  • 如何实现 font-size 的响应式
  • 如何邀请好友注册您的网站(模拟百度网盘)
  • 无服务器化是企业 IT 架构的未来吗?
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  •  一套莫尔斯电报听写、翻译系统
  • 国内开源镜像站点
  • ​14:00面试,14:06就出来了,问的问题有点变态。。。
  • # 数仓建模:如何构建主题宽表模型?
  • #define 用法
  • #define用法
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (C#)一个最简单的链表类
  • (done) 两个矩阵 “相似” 是什么意思?
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (接口自动化)Python3操作MySQL数据库
  • (实测可用)(3)Git的使用——RT Thread Stdio添加的软件包,github与gitee冲突造成无法上传文件到gitee
  • (译)2019年前端性能优化清单 — 下篇