系统调用:
由操作系统实现并提供给外部应用程序的编程接口,是应用程序同系统之间数据交换的桥梁
open 函数:
int open (char* pathname,int flags) #include<unistd.h>
参数:
pathname :欲打开的文件路径名
flags :文件的打开方式 : O_RDONLY | O_WRONLY | O_RDWR
O_CREAT|O_APPEND(追加)|O_TRUNC(文件清零)|O_EXCL|O_NONBLOCK(设置非阻塞)
返回值:
成功: 打开文件所得到的 对应 文件描述符(整数)
失败: -1 ,设置 errno
int open(char* pathname,int flags, mode_t mode)
open(pathname,O_RDONLY |O_CREAT ,0664);
参数:
pathname:欲打开文件路径名
flags: 文件打开方式: O_RDONLY | O_WRONLY | O_RDWR O_CREAT|O_APPEND|O_TRUNC|O_EXCL|O_NONBLOCK
mode: 参数3使用前提 惨2指定了 O_CREAT 取值8进制数,用来描述文件的访问权限
创建文件的最终权限 mode& ~umask
返回值:
成功: 打开文件所得到的 对应 文件描述符(整数)
失败: -1 ,设置 errno
close函数:
int close (int fd)
错误处理函数: 与errno相关
printf(“xxxerrno%d\n”,errno)
char* strerror(int errno)
printf("xxx error:%s\n",strerror(errno))
void perror(const char* s);
perror("open error");
read 函数:
ssize_t read(int fd,void* buf,size_t count);
参数:
fd:文件描述符
buf:存数据的缓冲区
count:缓冲区大小
返回值:
0:读到文件末尾
成功: 读到的字节数
失败:—1 设置errno 并且errno = EAGIN 或 EWOULDBLOCK ,说明不是read 失败,
而是read在以非阻塞的方式读一个设备文件或网络文件,并且文件无数据
write 函数:
ssize_t write(int fd,const void* buf,size_t count);
参数:
fd:文件描述符
buf:待写出数据的缓冲区
count:数据大小
返回值:
成功: 写入的字节数
失败:—1 设置errno
strace命令:
跟踪程序执行,查看调用的系统函数
read write 实现 cp
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
int main(int argc,char* argv[]){
(void) argc;
char buf[1024];
int n=0;
int fd1 = open(argv[1],O_RDONLY);
if (fd1==-1){
perror("open argv1 error");
exit(1);
}
int fd2 = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);
if (fd2==-1){
perror("open argv2 error");
exit(1);
}
while(n=read(fd1,buf,1024)){
printf("读到字节数:%d\n",n);
if(n<0){
perror("read error");
break;
}
write(fd2,buf,n);
}
close(fd1);
close(fd2);
return 0;
}
库函数和系统调用的比较
#include<stdio.h>
#include<stdlib.h>
int main(){
FILE* fp,*fp_out;
int n;
fp = fopen("dixt.txt","r");
if(fp==NULL){
perror("fopen error");
exit(1);
}
fp_out = fopen("dict.cp","w");
if(fp==NULL){
perror("fopen error");
exit(1);
}
while((n = fgetc(fp))!= EOF){
fputc(n,fp_out);
}
fclose(fp);
fclose(fp_out);
return 0;
}
include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
#include<errno.h>
#define N 1
int main(){
int fd,fd_out;
int n;
char buf[N];
fd = open("dixt.txt",O_RDONLY);
if(fd<0){
perror("open dict.txt error");
exit(1);
}
fd_out = open("dict.cp",O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fd<0){
perror("open dict.cp error");
exit(1);
}
while((n = read(fd,buf,N))){
if(n<0){
perror("read error");
exit(1);
}
write(fd_out,buf,n);
}
close(fd);
close(fd_out);
return 0;
}
预读入缓输出机制
结论
1.每一次读写操作都会发生用户态内核态转换 耗费时间较长
2.库函数 还有一个缓冲区 大小4096字节 切换状态少速度快
系统调用 每次读或写一个字节 频繁切换状态 速度慢。
因此 能用库函数尽量用库函数 ,数据较小时库函数 4096 缓冲区没满 通讯实时性无法得到保障 因此当一次性读写数据较少时用系统调用。
文件描述符:
pcb进程控制块 :本质 结构体
成员: 文件描述符表
文件描述符: 0/1/2/3/4/...1023 最小未使用
0 -STDIN__FILENO
1 -STDOUT_FILENO
2 -STDERR_FILENO
阻塞 非阻塞: 是设备文件、 网络文件的属性 不是read write 的属性
产生阻塞的场景 读设备文件 读网络文件 (常规文件无阻塞概念)
/dev/tty --终端文件
open("dev/tty",O_RDWR | O_NOBLOCK) --设置/dev/tty 非阻塞状态(默认为阻塞状态)
fcntl:
int flgs = fcntl(fd ,F_GETFL)
flgs |= O_NONBLOCK
fcntl(fd,F_SETFL,flgs)
获取文件状态: F_GETFL
设置文件状态: F_SETFL
lseek函数:
off_t lseek(int fd,off_t offset,int whence);
参数:
fd:文件描述符
offset:偏移量
whence:起始偏移位置,SEEK_SET(起始)/SEEK_CUR(当前)/SEEK_END(末尾)
返回值:
成功: 较起始位置偏移量
失败:-1 errno
应用场景:
1.文件的“读”、“写”使用同一偏移位置
列如:先read 10字节 再write时 从第11字节开始写
//文件的“读”、“写”使用同一偏移位置
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
int main(){
char* buf = "woxiangnile\n";
int n;
char ch;
int fd = open("lseek.txt",O_RDWR | O_CREAT,0664);
write(fd,buf,strlen(buf));
//将光标移到起始位置
lseek(fd,0,SEEK_SET);
while(n=read(fd,&ch,1)){
if(n==-1){
perror("read errro");
}
write(STDOUT_FILENO,&ch,n);
}
return 0;
}
2.使用lseek获取文件大小
//使用lseek获取文件大小
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main(int argc,char* argv[]){
(void)argc;
int fd = open(argv[1],O_RDWR);
if(fd==-1){
perror("open error");
exit(1);
}
int lenth = lseek(fd,0,SEEK_END);
printf("file size:%d\n",lenth);
close(fd);
return 0;
3.使用lseek 拓展文件大小 要想使文件大小真正拓展,必须引起IO操作。
使用 truncate 函数,直接拓展文件 int ret = truncate(“dict.cp”,250)
将文件的大小拓展为 250
//将文件拓展增加 101个字节
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main(int argc,char* argv[]){
(void)argc;
int fd = open(argv[1],O_RDWR);
if(fd==-1){
perror("open error");
exit(1);
}
int lenth = lseek(fd,100,SEEK_END);
printf("file size:%d\n",lenth);
write(fd,"a",1);
close(fd);
return 0;
}
传入参数:
1.指针作为函数参数
2.用const修饰
3.指针指向有效区域,在函数内部做读操作
传出参数:
1.指针作为函数参数
2.在函数调用之前,指针指向的空间可以无意义,但必须有效
3.在函数内部,写操作
4.函数调用结束后,充当函数返回值
传入传出参数:
1.指针作为函数参数
2,在函数调用之前,指针指向的空间有实际意义
3.在函数内部,先做读操作,后做些操作
4.函数调用结束后,充当函数返回值。
来源:CSDN
作者:我喜欢的人很优秀
链接:https://blog.csdn.net/weixin_44374280/article/details/104242803