Linux基础-Linux系统函数
linux下应用层的系统I/O函数
-
man文档使用
man man :打开man文档目录 man 3 printf: 查找man文档第3章中的printf函数 man 2 open:查看man文档第2张的open函数
- 查看man文档时会看到很多的陌生数据类型,比如:size_t
- 因为man文档是nuix下面的,unix早于C语言,unix用C语言重写之前就有自己的数据类型。所以那些陌生类型就是Unix的数据类型,但是他跟C语言的基本数据类型本质一样。比如size_t就是int
-
open函数
//文件已经存在 int open(const char *pathname, int flags); //文件不存在 int open(const char *pathname, int flags, mode_t mode);
- pathname :要打开的文件路径
-
flags:要打开的方式
The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. The file creation flags are O_CLOEXEC,O_CREAT,O_DIRECTORY,O_EXCL,O_NOCTTY, O_NOFOLLOW, O_TMPFILE, and O_TRUNC.
- mode:这个调用方式是用于文件不存在调用方式
- 给创建文件制定访问权限
-
返回值:
//返回一个新的文件描述符。或者-1,如果为-1就是错误发生(在这种情况下,有个全局变量errno就会被赋值。可以通过errno的值来判别错误的具体原因) open(), openat(), and creat() return the new file descriptor, or -1 if an error occurred (in which case, errno is set appropriately).
- errno是linux系统的全局变量,专门用于标记错误类型。
- 通过
void perror(const char *s)
函数来获取到errno的具体错误内容 - 使用perror函数时,会先读取errno的值,然后就会把错误原因输出到标准设备(stderr)
- 参数s所指的字符串会先打印出,后面再加上错误原因字符串
- 错误原因依照全局变量errno的值来决定要输出的字符串
- errno的声明在errno.h头文件中:
vi /usr/include/errno.h
- 通过
-
open函数的使用
#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> #include<stdlib.h> #include<stdio.h> int main() { int fd; //打开一个已经存在的文件 //2K(shift+k)跳转到man文档中open函数 fd = open("add.c",O_RDWR); if(fd==-1) { perror("open file"); exit(1); } //打开一个不存在的文件 fd = open("hello",O_RDWR | O_CREAT,0777); if(fd==-1) { perror("open file"); exit(1); } printf("fd=%d",fd); // int ret = close(fd); printf("ret = %d",ret); if(ret=-1) { perror("close file"); } return 0; }
- read和write函数
-
查看man文档:
man 2 read
//锁需要包含的头文件 #include <unistd.h> //ssize_t 有符号整型 ssize_t read(int fd, void *buf, size_t count);
- fd:文件描述符
- buf:需要用户提供的缓冲区
- 每次读数据用多大的buf
-
返回值:
-1:读取失败了 0: 文件读完了 >0: 读取的字节数
- 同理文件读取的错误信息,会赋值给errno
-
查看man文档:
man 2 write
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);
- 将buf中的内容写到磁盘上
-
查看man文档:
man 2 lseek
#include <sys/types.h> #include <unistd.h> off_t lseek(int fd, off_t offset, int whence);
- 作用:移动文件指针,获取文件长度
- offset:文件指针的偏移量
-
读取代码示例:(将一个文件的内容读取出来,然后写到一个新的文件中)
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main() { // 打开一个已经存在的文件 int fd = open("english.txt",O_RDONLY); if(fd == -1) { perror("openfile"); exit(1); } //创建一个新的文件 ----写操作 int fd1 = open("newenglisht.txt",O_CREAT | O_WRONLY,0664); if(fd1 == -1) { perror("opennewfile"); exit(1); } //读文件 //手动定义缓冲区,缓冲区读完,刷新 char buf[2048] = {0}; //count= 0;文件读取完了,cont = -1 读取错误,count>0文件读取的字节数 int count = read(fd,buf,sizeof(buf)); if(count == -1) { perror("read error"); exit(1); } while(count) { //将读出的数据写入新的文件中 int ret = write(fd1,buf,count); printf("write bytes %d \n",ret); count = read(fd,buf,sizeof(buf)); } //关闭文件 close(fd); close(fd1); return 0; }
-
- lseek函数
- 作用:
- 获取文件大小
- 移动文件指针
- 文件拓展
-
使用:
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main() { int fd = open("aa",O_RDWR); if(fd == -1) { perror("open"); exit(1); } //获取文件长度 int ret = lseek(fd,0,SEEK_END); printf("file len = %d \n",ret); //文件拓展:把一个文件拓展成更大的文件。 //从文件最后拓展2000byte int ret2 = lseek(fd,2000,SEEK_END); printf("return value %d \n",ret2); //实现文件拓展,必须在最后作一次写的操作 write(fd,"a",1); close(fd); return 0; }
- 作用:
linux下的文件操作函数
linux的文件操作系统函数都有对应的命令,比如:stat函数对应stat命令‘
stat函数
- 作用:获取文件的属性信息,对应命令:
stat
-
举例:命令使用
stat english.txt
文件:english.txt 大小:95 块:8 IO 块:4096 普通文件 设备:802h/2050d Inode:921171 硬链接:1 权限:(0644/-rw-r--r--) Uid:( 1000/coderzhong) Gid:( 1000/coderzhong) 最近访问:2019-11-04 11:04:19.947951850 +0800 最近更改:2019-11-04 10:37:57.979086559 +0800 最近改动:2019-11-04 10:37:57.979086559 +0800 创建时间:-
- 列出文件的属性信息
- Inode:对于操作系统来说,它对文件名不感兴趣,只对Inode感兴趣,每个文件都对应一个Inode号,操作系统通过这个Inode号找到对应的磁盘位置
-
查看
man 2 stat
//依赖的头文件 #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> //函数声明 int stat(const char *pathname, struct stat *statbuf); int fstat(int fd, struct stat *statbuf); int lstat(const char *pathname, struct stat *statbuf);
- stat参数说明:
- pathname:文件的路径
- statbuf:stat类型的结构体指针
-
stat结构体:
struct stat { dev_t st_dev; //文件的设备编号 ino_t st_ino; //节点 mode_t st_mode; //文件的类型和存取的权限(重点!!!) nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1 uid_t st_uid; //用户ID gid_t st_gid; //组ID dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号 off_t st_size; //文件字节数(文件大小) blksize_t st_blksize; //块大小(文件系统的I/O 缓冲区大小) blkcnt_t st_blocks; //块数 time_t st_atime; //最后一次访问时间 time_t st_mtime; //最后一次修改时间 time_t st_ctime; //最后一次改变时间(指属性) };
- st_mode
- 改变量占2个字节,16位
-
采用位域存储技术来存储信息
-
其他人权限(0-2 bit)
S_IROTH 00004 读权限 二进制:100 S_IWOTH 00002 写权限 二进制: 010 S_IXOTH 00001 执行权限 二进制:001 掩码:S_IRWXO 00007 过滤 st_mode中除其他人权限以外的信息 本质就是让st_mode与111相与,获取后3位的值
-
所属组权限(3-5 bit)
S_IRGRP 00040 读权限 二进制;100000 S_IWGRP 00020 写权限 二进制:010000 S_IXGRP 00010 执行权限 二进制:001000 掩码:S_IRWXG 00070 过滤 st_mode中除所属组权限以外的信息 对应二进制:111000
-
文件所有者权限(6-8 bit)
S_IRUSR 00400 读权限 S_IWUSR 00200 写权限 S_IXUSR 00100 执行权限 掩码:S_IRWXU 00700 过滤 st_mode中除文件所有者权限以外的信息
-
特殊权限位(9-11 bit)
S_ISUID 0004000 设置用户ID S_ISGID 0002000 设置组ID S_ISVTX 0001000 黏住位 很少用
-
文件类型(12-15 bit)
S_IFSOCK 0140000 套接字 S_IFLNK 0120000 符号链接(软链接) S_IFREG 0100000 普通文件 S_IFBLK 0060000 块设备 S_IFDIR 0040000 目录 S_IFCHR 0020000 字符设备 S_IFIFO 0010000 管道 掩码:S_IFMT 0170000 过滤 st_mode中除文件类型以外的信息 if(S_IFMT & st_mode == S_IFSOCK)
-
- stat参数说明:
-
使用:
#include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdio.h> #include<stdlib.h> int main(int argc,char *argv[]) { struct stat st; int ret = stat("english.txt",&st); if(ret == -1) { perror("stat"); exit(1); } //获取文件的大小 int size =(int) st.st_size; printf("file size = %d \n",size); //查看文件的类型 if((st.st_mode & S_IFMT) == S_IFREG) { printf("这个文件是一个普通文件\n"); } //所有者对文件的操作权限 if(st.st_mode & S_IRUSR) { printf("----r\n"); } if(st.st_mode & S_IWUSR) { printf("----w\n"); } if(st.st_mode & S_IXUSR) { printf("----x\n"); } return 0; }
- 编译:
gcc stat.c -o stat
- 运行:
./stat
-
打印:
file size = 95 这个文件是一个普通文件 ----r ----w
- 编译:
- lstat与stat的区别
- 区别在于读链接文件(快捷方式,ln-s创建出来的)时候
- 比如:终端输入
ln -s english.txt s.s
- 这样会创建一个english.txt文件的快捷方式s.s
-
将上面的代码读取文件english.txt换成s.s,然后执行
file size = 95 这个文件是一个普通文件 ----r ----w
- 这应该是一个链接文件
- 文件大小也不对
-
将上面的读取方式由stat换成lstat则
file size = 11 ----r ----w ----x
- 这里没有打印“普通文件”,说明不是普通文件
- 大小也变化了
- 总结:
- stat 在读链接文件时,实际上读的是链接文件指向的实际文件的属性
- lstat 读取链接文件时,读取的就是链接文件的属性。
- fstat函数
- 第一个参数是文件描述符fd
- 用于获取有文件描述符fd的文件属性
- 比如用open函数打开一个文件,那么就可以用这个返回的文件描述符fd,来查看文件的属性
其他函数
- access函数
- 作用:测试文件有哪些权限
- 原型:
int access(const char *pathname, int mode);
- 参数:
- pathname : 文件名
- mode: 权限类别
- R_OK 是否有读权限
- W_OK 是否有写权限
- X_OK 是否有执行权限
- F_OK 测试一个文件是否存在
- 返回值
- 0 : 所有欲查核的权限都通过了检查
- -1 :有权限被禁止
- 其他函数:
chmode、chown、truncate、link、symlink、readlink、unlink
linux下的目录操作函数
rename :重命名
chdir:修改当前进程的路径
getcwd:获取当前进程工作目录
mkdir:创建目录
rmdir:删除一个目录
opendir:打开目录
readdir:读目录
closedir:关闭目录
dup和dup2函数
- 作用: 复制现有的文件描述符
-
man dup
#include <unistd.h> int dup(int oldfd); //返回的是文件描述符表中没有被占用的最小的文件描述符 oldfd:要复制的文件描述符 返回值:新的文件描述符 dup调用成功:有2个文件描述符指向同一个文件 int dup2(int oldfd, int newfd); newfd分2种情况 1. newfd已经指向了一个文件(文件描述符的重定向) 1. 首先要断开close与原来文件的连接 2. newfd指向oldfd指向的文件 3. 注意:如果old和new指向了同一个文件,那么不需要close,直接返回 2. newfd没有指向一个文件 1. newfd指向oldfd指向的文件
-
代码举例:
#include<string.h> #include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> int main(void) { //打开一个文件temp,如果不存在就创建一个。 int fd = open("temp",O_RDWR | O_CREAT,0664); if(fd==-1) { perror("open"); exit(1); } //复制文件描述符 int fd2 = dup(fd); //int fd2 = fcntl(fd,F_DUPFD); //写文件 char* p = "让编程改变世界"; write(fd2,p,strlen(p)); close(fd2); char buf[1024]; //将文件指针移动到文件头部 lseek(fd,0,SEEK_SET); read(fd,buf,sizeof(buf)); printf("buf = %s \n",buf); close(fd); }
fcntl函数
- 作用: 改变已经打开的文件的属性。根据文件描述符来操作文件的状态
-
函数原型
#include <fcntl.h> int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock);
- 使用
-
复制一个已有的文件描述符
int fcntl(fd, F_DUPFD);
-
获取、设置文件状态标志
- open的flags参数
-
获取文件状态标识
int flag = fcntl(fd,F_GETFL);
-
设置文件状态标识
flag = flag | O_APPEND; fcntl(fd,F_SETFL,flag);
- 可以更改的几个标识:
O_APPEND、O_NONBLOCK(常用)
-