Linux文件,目录IO类系统调用总结与示例
创始人
2024-05-24 04:55:24
0

tags: C Syscall Linux

写在前面

无论是做网络编程还是系统编程, 逃不开的一个内容就是C系统调用的学习, 正如C++的STL一样, 学习OS也有如下的三步骤:

  1. 会使用: 熟悉API
  2. 懂原理: 分析源码
  3. 写扩展: 实际开发

现在就来熟悉一下系统调用吧. 环境Ubuntu x86_64.

源码部分也参考了apue以及Linux/UNIX系统编程手册.

预备知识

什么是系统调用

  1. 系统调用将处理器从用户态切换到核心态, 以便让CPU访问受到保护的内核内存数据.
  2. 其组成是固定的, 每一个系统调用都由唯一一个数字来标识.

程序运行四区

截屏2023-02-04 00.37.08.jpg

非常重要, 全图背诵.

标准文件描述符

文件描述符用途POSIX名称stdio流
0标准输入STDIN_FILENOstdin
1标准输出STDOUT_FILENOstdout
2标准错误STDERR_FILENOstderr

针对stdout调用freopen()函数后,无法保证stdout变量值仍然为1。

常用头文件

头文件包括的常用函数/常量作用
sys/types.h类型定义
sys/stat.h状态定义
stdio.hprintf,fprintf标准I/O函数
stdlib.hmalloc,free标准库函数
unistd.hsleep,部分系统调用
errno.h错误状态码
string.hmemset,strcpy字符创相关操作
(堆内存分配与初始化)
limits.hINT_MAX系统限制
fcntl.hfcntl,文件I/O函数(高级)

文件I/O

文件访问模式

常用的文件访问模式如下表.

访问模式描述访问模式描述
O_RDONLY只读打开O_CREAT不存在则创建
O_WRONLY只写打开O_TRUNC截断已有文件
(长度置为0)
O_RDWR读写打开O_APPEND文件尾部追加

备注:

  1. 调用open()时, O_RDONLY、O_WRONLY和O_RDWR标志在flags参数中不能同时使用,只能指定其中一种
  2. O_TRUNC: 如果文件已经存在且为普通文件,那么将清空文件内容,将其长度置0。在Linux下使用此标志,无论以读、写方式打开文件,都可清空文件内容(在这两种情况下,都必须拥有对文件的写权限)

权限位

权限位st_mode含义八进制值英文注记
S_IRUSR用户读4READ USER
S_IWUSR用户写2WRITE USER
S_IXUSR用户执行1EXEC USER
S_IRGRP组读4READ GROUP
S_IWGRP组写2WRITE GROUP
S_IXGRP组执行1EXEC GROUP
S_IROTH其他用户读4READ OTHER
S_IWOTH其他用户写2WRITE OTHER
S_IXOTH其他用户执行1EXEC OTHER

例如常用的可执行文件权限位: 755, 就对应了rwx-r-xr-x, 而默认创建目录的权限位为:

open: 创建文件

fd = open(pathname, flags, mode) 函数打开pathname所标识的文件,并返回文件描述符,用以在后续函数调用中指代打开的文件。如果文件不存在,open()函数可以创建之,这取决于对位掩码参数flags的设置。

#include 
#include 
#include 
#include 
#include void error_handling(char* msg);int fd;
void t1() {// create and writechar buf[] = "Let's go!";fd = open("data", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);if (fd == -1) error_handling("open() error");printf("file descripter: %d\n", fd);if (write(fd, buf, sizeof(buf)) == -1) error_handling("write() error");close(fd);
}
void t2() {// append to logchar buf[] = "abc\n";fd = open("log", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);if (fd == -1) error_handling("open() error");printf("file descripter: %d\n", fd);if (write(fd, buf, sizeof(buf)) == -1) error_handling("write() error");close(fd);
}int main(int argc, char* argv[]) {t1();t2();return 0;
}void error_handling(char* msg) {fputs(msg, stderr);fputc('\n', stderr);/* printf("aa\n"); */exit(1);
}

read: 读出流

#include 
#include 
#include 
#include 
#include void t1() {int fd = open("data", O_RDONLY);char buf[100];read(fd, buf, 10);printf("buf=%s\n", buf); // buf=Let's go!close(fd);
}
int main(int argc, char *argv[]) {t1();return 0;
}

write: 写入流

例子见open().

close: 关闭文件

lseek: 改变文件偏移量

对于每个打开的文件,系统内核会记录其文件偏移量,有时也将文件偏移量称为读写偏移量或指针。文件偏移量是指执行下一个read()或write()操作的文件起始位置,会以相对于文件头部起始点的文件当前位置来表示。文件第一个字节的偏移量为0。

文件打开时,会将文件偏移量设置为指向文件开始,以后每次read()或write()调用将自动对其进行调整,以指向已读或已写数据后的下一字节。因此,连续的read()和write()调用将按顺序递进,对文件进行操作。
针对文件描述符fd参数所指代的已打开文件,lseek()系统调用依照offset和whence参数值调整该文件的偏移量。

offset参数指定了一个以字节为单位的数值。(SUSv3规定off_t数据类型为有符号整型数。)whence参数则表明应参照哪个基点来解释offset参数,应为下列其中之一:

  • SEEK_SET: 将文件偏移量设置为从文件头部起始点开始的offset个字节
  • SEEK_CUR: 相对于当前文件偏移量,将文件偏移量调整offset个字节.
  • SEEK_END: 将文件偏移量设置为起始于文件尾部的offset个字节。也就是说,offset参数应该从文件最后一个字节之后的下一个字节算起.
#include 
#include 
#include 
#include 
#include void t1() {int fd = open("data", O_WRONLY, S_IWUSR);int cur = lseek(fd, 0, SEEK_CUR);printf("cur seek = %d\n", cur);cur = lseek(fd, 2, SEEK_SET);printf("cur seek = %d\n", cur);
}int main(int argc, char *argv[]) {t1();return 0;
}

文件信息

#include 
#include 
#include int main(int argc, char *argv[]) {struct stat sb;if (stat("data", &sb) == -1) fprintf(stderr, "stat-error");printf("size=%ld\n", sb.st_size);printf("mode=%u\n", sb.st_mode);printf("uid=%u\n", sb.st_uid);printf("gid=%u\n", sb.st_gid);printf("hard link number=%ld\n", sb.st_nlink);putchar('\n');printf("dev-id=%ld\n",sb.st_dev);printf("rdev-id=%ld\n", sb.st_rdev);printf("i-node=%ld\n", sb.st_ino);printf("block-size=%ld\n", sb.st_blksize);printf("blocks=%ld\n", sb.st_blocks);putchar('\n');printf("last access time=%s", ctime(&sb.st_atime));printf("last modify time=%s", ctime(&sb.st_mtime));printf("last status change time=%s\n", ctime(&sb.st_ctime));return 0;
}
/* size=10 */
/* mode=33152 */
/* uid=1001 */
/* gid=1001 */
/* hard link number=1 */
/*  */
/* dev-id=64513 */
/* rdev-id=0 */
/* i-node=1212099 */
/* block-size=4096 */
/* blocks=8 */
/*  */
/* last access time=Thu Feb  9 17:42:47 2023 */
/* last modify time=Sun Feb  5 01:19:56 2023 */
/* last status change time=Sun Feb  5 01:19:56 2023 */ 

目录I/O

mkdir: 创建目录

#include 
#include 
#include 
#include // rw-r--r--
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
// rwxrwxr-x
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IWGRP | S_IXGRP | S_IXOTH)int main(int argc, char *argv[]) {mkdir("new_dir", DIR_MODE);return 0;
}

getpwd: 获取当前目录

#include 
#include 
#include 
#include int main(int argc, char *argv[]) {char *ptr;size_t size = 100;ptr = (char *)malloc(size);getcwd(ptr, size);printf("cwd = %s\n", ptr); // cwd = /home/zorch/code/c_cpp_code/syscall/dirioreturn 0;
}

chdir: 更改当前目录

#include 
#include 
#include 
#include int main(int argc, char *argv[]) {char *ptr;size_t size = 100;ptr = (char *)malloc(size);chdir("/usr/local/lib");getcwd(ptr, size);printf("cwd = %s\n", ptr); // cwd = /usr/local/libreturn 0;
}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...