网站宣传的劣势,平台运营推广方案,快速排名优化怎么样,怎么看网站用哪个系统做的一、系统调用
由操作系统实现并提供给外部应用程序的编程接口(Application Programming Interface#xff0c;API),用户程序可以通过这个特殊接口来获得操作系统内核提供的服务
系统调用和库函数的区别#xff1a; 系统调用(系统函数) 内核提供的函数 库调用 …一、系统调用
由操作系统实现并提供给外部应用程序的编程接口(Application Programming InterfaceAPI),用户程序可以通过这个特殊接口来获得操作系统内核提供的服务
系统调用和库函数的区别 系统调用(系统函数) 内核提供的函数 库调用 程序库中的函数 错误处理函数
errno用于记录系统的最后一次错误代码返回一个int值(错误码)在errno.h中定义不同的错误码表示不同的含义新建errno.c如下
#includestdio.h
#includeerrno.h
#includestring.hint main(void)
{FILE *fp fopen(txt,r);//打开一个不存在的文件if (NULL fp){printf(fopen failed\n);printf(errno:%d\n,errno);//打印errno返回的错误码printf(fopen:%s\n,strerror(errno));//使用strerror函数来解释错误码return 1;}return 0;
}编译再执行可得如下结果 fopen failed errno:2 fopen:No such file or directory 虚拟地址空间 文件描述符
当我们打开文件或者新建文件时系统会返回一个文件描述符用来指定已打开的文件这个文件描述符相当于这个已打开文件的标号操作这个文件描述符就相当于操作这个描述符所指定的文件程序运行起来后每个进程都有一张文件描述符的表标准输入、输出标准错误输出对应的文件描述符0、1、2就记录在表中程序运行起来后这三个文件描述符是默认打开的 文件描述符是指向一个文件结构体的指针
进程控制块(PCB)本质---结构体
FILE结构体主要包含文件描述符、文件读写位置、IO缓冲区三部分内容
最大打开文件数一个进程默认打开文件的个数1024 命令查看ulimit -a 查看open files 对应值。默认为1024 可以使用ulimit -n 4096 修改 cat /proc/sys/fs/file-max可以查看该电脑最大可以打开的文件个数。受内存大小影响。 二、常用文件IO函数
1.open函数 #include sys/types.h #include sys.stat.h #include fcntl.h int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); 参数 pathname: 欲打开的文件路径名 flags文件打开方式 #include fcntl.h O_RDONLY|O_WRONLY|O_RDWR O_CREAT|O_APPEND|O_TRUNC|O_EXCL|O_NONBLOCK .... mode这个参数只有在文件不存在时有效,指新建文件时指定文件的权限 取值8进制数用来描述文件的访问权限。 rwx 0664 创建文件最终权限 mode ~umask 返回值 成功 打开文件所得到对应的 文件描述符整数 失败 -1 设置errno flags必选项 O_RDONLY 以只读的方式打开 O_WRONLY 以只写的方式的打开 O_RDRW 以可读、可写的方式打开 可选项和必选项进行位或(|) O_CREAT 文件不存在则创建文件使用此选项时需使用mode说明文件的权限 O_EXCL 如果同时指定了O_CREAT且文件已经存在则出错 O_TRUNC 如果文件存在则清空文件内容 O_APPEND 写文件时数据添加到文件末尾 O_NONBLOCK 对于设备文件以O_NONBLOCK方式打开可以做非阻塞I/O 打开dict.cp如果不存在则创建并添加权限如果存在则清空内容
#includeunistd.h
#includefcntl.h
#includestdio.hint main(int argc,char *argv[])
{int fd;open(./dict.cp,O_RDONLY | O_CREAT | O_TRUNC,0644);//rw-r--r--printf(fd %d\n,fd);close(fd);return 0;
}对于存在mydir目录以及不存在mydir目录执行以下程序
#includeunistd.h
#includefcntl.h
#includestdio.h
#includeerrno.h
#includestring.hint main(int argc,char *argv[])
{int fd;open(mydir,O_WRONLY);printf(fd %d,errno %d:%s\n,fd,errno,strerror(errno));close(fd);return 0;
}mydir目录存在输出为 fd 21991,errno 21:Is a directory mydir目录不存在输出为 fd 22002,errno 2:No such file or directory 2.close函数 #include unistd.h int close(int fd); 功能 关闭已打开的文件 参数 fd文件描述符open()的返回值 返回值 成功0 失败-1并设置errno 3.write函数 #include unistd.h ssize_t write(int fd, const void *buf, size_t count); 功能 把指定数目的数据写到文件(fd) 参数 fd文件描述符 buf数据首地址 count写入数据的长度(字节) 返回值 成功实际写入数据的字节个数 失败-1 4.read函数 #include unistd.h ssize_t read(int fd, void *buf, size_t count); 功能 把指定数目的数据读到内存(缓冲区) 参数 fd文件描述符 buf内存首地址 count读取的字节个数 返回值 成功实际读取到的字节个数 失败-1 用read和write实现一个copy函数
#includestdio.h
#includestdlib.h
#includestring.h
#includeunistd.h
#includepthread.h
#includefcntl.hint main(int argc,char *argv[])
{char buf[1024];int n 0;int fd1 open(argv[1],O_RDONLY);//readif (fd1 -1){perror(open argv1 error);exit(1);}int fd2 open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0644);if (fd2 -1){perror(open argv2 error);exit(1);}while((n read(fd1,buf,1024)) ! 0){if (n 0){perror(read error);break; }write(fd2,buf,n);}close(fd1);close(fd2);return 0;
}5.lseek函数 #include sys/types.h#include cunistd.h off_t lseek(int fdoff_t offsetint whence); 功能: 改变文件的偏移量(读写位置) 参数: fd:文件描述符 offset:根据whence来移动的位移数偏移量)可以是正数也可以负数如果正数则相对于whence往右移动如果是负数则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。 whence:其取值如下: SEEK_SET:从文件开头移动offset个字节 SEEK_CUR:从当前位置移动offset个字节 SEEK__END:从文件未尾移动offset个字节 返回值: 若lseek成功执行,则返回新的偏移量 如果失败,返回-1 lseek允许超过文件结尾设置偏移量文件会因此被拓展。
使用lseek获取文件大小
#includestdio.h
#includestdlib.h
#includefcntl.h
#includestring.h
#includeunistd.h
#includepthread.hint main(int argc,char *argv[])
{int fd open(argv[1],O_RDWR);if (fd -1){perror(read error);exit(1);}int lenth lseek(fd,0,SEEK_END);//获取文件大小printf(file size:%d\n,lenth);close(fd);return 0;
}make之后执行 ./lseek_test dict.c 可得到dict.c的文件大小 out file size:48 使用lseek扩展文件大小
#includestdio.h
#includestdlib.h
#includefcntl.h
#includestring.h
#includeunistd.h
#includepthread.hint main(int argc,char *argv[])
{int fd open(argv[1],O_RDWR);if (fd -1){perror(read error);exit(1);}int lenth lseek(fd,52,SEEK_END);//扩展文件大小printf(file size:%d\n,lenth);write(fd,a,1);close(fd);return 0;
}make之后执行 ./lseek_test dict.c 可得到dict.c的文件大小再执行ls -l dict.c得到扩展之后的文件大小输出分别为 file size:100 -rw-rw-r-- 1 *** *** 101 *** ** *** dict.c 应用场景
1. 文件的“读”、“写”使用同一偏移位置。
2. 使用lseek获取文件大小返回值接收
3. 使用lseek拓展文件大小要想使文件大小真正拓展必须【引起IO操作】(即write)。
使用 truncate 函数直接拓展文件。 int ret truncate(dict.cp”,250): #includestdio.h
#includeunistd.h
#includestring.h
#includestdlib.h
#includepthread.hint main(int argc,char *argv[])
{//open/lseek(fd,249.SEED_END)/write(fd,\0,1);int ret truncate(dict.cp,200);printf(ret %d\n,ret);return 0;
}起始cidt.cp文件大小为0经过以上代码扩展之后cidt.cp文件大小为200
三、系统调用和库函数比较---预读入缓输出 fputc/fgetc实现
int main(void){FILE *fp,*fp_out;int n 0;fp fopen( hello.c , r);if(fp NULL){perror( fopen error );exit( 1);}fp_out fopen ( hello.cp ,w );if(fp_out NULL){perror( fopen error );exit(1);}while((n fgetc(fp))! EOF){fputc(n, fp_out) ;}fclose(fp);fclose(fp_out);return 0;
}
read/write实现
int main( int argc, char *argv[])
{char buf[ 1];int n 0;int fd1 open(argv[1]0_RDONLY);int fd2 open(argv[2]O_RDWR|0_CREAT|0_TRUNC0664);while((n read (fd1,buf,1)) ! 0){write(fd2, buf, n);}close(fd1);close(fd2);return 0;
}
结果表明read/write速度慢
原因分析
read/write这块每次写一个字节会疯狂进行内核态和用户态的切换所以非常耗时。fgetc/fputc有个缓冲区4096所以它并不是一个字节一个字节地写内核和用户切换就比较少
预读入缓输出机制。所以系统函数并不是一定比库函数牛逼能使用库函数的地方就使用库函数。
标准IO函数自带用户缓冲区系统调用无用户级缓冲。系统缓冲区是都有的。
四、阻塞和非阻塞
产生阻塞的场景读设备文件。读网络文件的属性。读常规文件无阻塞概念
/dev/tty -- 终端文件。
open(/dev/tty, O_RDWR | O_NONBLOCK) --- 设置 /dev/tty 非阻塞状态。(默认为阻塞状态)
更改非阻塞读取终端——超时设置
#include unistd.h
#include fcntl.h
#include stdlib.h
#include stdio.h
#include errno.h
#include string.h #define MSG_TRY try again\n
#define MSG_TIMEOUT time out\n int main(void)
{ //打开文件int fd, n, i; fd open(/dev/tty, O_RDONLY | O_NONBLOCK); if(fd 0){ perror(open /dev/tty); exit(1); } printf(open /dev/tty ok... %d\n, fd); //轮询读取char buf[10]; for (i 0; i 5; i){ n read(fd, buf, 10); if (n 0) { //说明读到了东西 break; } if (errno ! EAGAIN) { //EWOULDBLOCK perror(read /dev/tty); exit(1); } else { write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY)); sleep(2); } } //超时判断if (i 5) { write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT)); } else { write(STDOUT_FILENO, buf, n); } //关闭文件close(fd); return 0;
}
五、传入传出参数 传入参数 1. 指针作为函数参数。 2. 同常有const关键字修饰。 3. 指针指向有效区域 在函数内部做读操作。 传出参数 1. 指针作为函数参数。 2. 在函数调用之前指针指向的空间可以无意义但必须有效。 3. 在函数内部做写操作。 4。函数调用结束后充当函数返回值。 传入传出参数 1. 指针作为函数参数。 2. 在函数调用之前指针指向的空间有实际意义。 3. 在函数内部先做读操作后做写操作。 4. 函数调用结束后充当函数返回值。