一、Linux系统调用及用户编程接口(API)
errno(error+number)——错误代码,自动赋值
当linux中的 api函数发生异常时,一般会将errno变量(需include errno.h)赋一个整数值,不同的值表示不同的含义,可以通过查看该值推测出错的原因
1、系统调用
操作系统提供给用户的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的的服务
系统调用并不是直接与程序员进行交互的,它仅仅是一个通过软中断机制向内核提交请求,以获取内核服务的接口。在实际使用中程序员调用的通常是用户编程接口—API
系统命令相对API更高了一层,它实际上一个可执行程序,它的内部引用了用户编程接口(API)来实现相应的功能
2、用户程序不能直接访问系统内核提供的服务的原因
由于在Linux中,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间(也就是常称的内核态和用户态),它们分别运行在不同的级别上,在逻辑上是相互隔离的。因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。
核心(Kernel)的基础功能
二、Linux中文件及文件描述符概述
1、Linux文件
-
Linux一点哲学
- “一切皆为文件”;在Linux中对目录和设备的操作都等同于对文件的操作;
-
查看Linux文件类型(无后缀和扩展名)
- ls-l/ls-ld 或者ll [ls-l —查看文件 ls-ld —查看路径 ll ----跟ls -l 一样]
-
ll anaconda-ks.cfg //看第一个字符 -rw-------. 1 root root 2460 6月 1 23:37 anaconda-ks.cfg [root@localhost log]# ls -ld /etc drwxr-xr-x. 81 root root 4096 Jan 29 03:25 /etc
- file 命令
-
[root@localhost data]# file a.txt a.txt: ASCII text
- stat 命令
-
[root@localhost data]# stat a.txt //查看文件的详细属性(其中包括文件时间属性) File: `a.txt' Size: 3 Blocks: 8 IO Block: 4096 regular file Device: 803h/2051d Inode: 544365 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2018-01-28 20:56:01.965885036 +0800 Modify: 2018-01-28 20:55:27.181876154 +0800 Change: 2018-01-28 20:55:27.181876154 +0800
-
Linux文件可分为:普通文件,目录文件,链接文件,设备文件;
①普通文件类型
Linux中最多的一种文件类型, 包括 纯文本文件(ASCII);二进制文件(binary);数据格式的文件(data);各种压缩文件.第一个属性为 [-]
②目录文件
就是目录, 能用 # cd 命令进入的。第一个属性为 [d],例如 [drwxrwxrwx]
③块设备文件
块设备文件 : 就是存储数据以供系统存取的接口设备,简单而言就是硬盘。例如一号硬盘的代码是 /dev/hda1等文件。第一个属性为 [b]
④字符设备
字符设备文件:即串行端口的接口设备,例如键盘、鼠标等等。第一个属性为 [c]
⑤套接字文件
这类文件通常用在网络数据连接。可以启动一个程序来监听客户端的要求,客户端就可以通过套接字来进行数据通信。第一个属性为 [s],最常在 /var/run目录中看到这种文件类型
⑥管道文件
FIFO也是一种特殊的文件类型,它主要的目的是,解决多个程序同时存取一个文件所造成的错误。FIFO是first-in-first-out(先进先出)的缩写。第一个属性为 [p]
⑦链接文件
类似Windows下面的快捷方式。第一个属性为 [l],例如 [lrwxrwxrwx]⑧堆栈文件
如LIFO。第一个属性为[f].
2、文件描述符(文件id——动态分配:只要当操作这个文件时,系统才会给你分配文件描述符)
- 文件描述符是一个非负的整数(从0开始),它是一个索引值,并指向内核中每个进程的记录表中;
- 从3编号开始,0,1,2文件描述符有其他作用
- 一个进程启动时,都会打开三个文件:
- 标准输入: STDIN_FILENO 0
- 标准输出: STDOUT_FILENO 1
- 标准出错处理:STDERR_FILENO 2
- 输入和输出
- 头文件:<nuisted.h>
- unistd.h是unix std的意思,是POSIX标准定义的unix类系统定义符号常量的头文件,包含了许多UNIX系统服务的函数原型,例如read函数、write函数和getpid函数。
- 实现代码
-
因为输入有换行符,只能读入5个,所以会出错👉[root@localhost 0223]
改为6
-
- 头文件:<nuisted.h>
三、无缓冲访问文件(系统调用)——无缓冲指每一个函数都只调用系统中的一个函数
1、系统调用
-
创建
- int creat(const char *filename,mode_t mode)
- filename:创建的文件名
- mode:创建模式,权限
-
常创建模式 S_IRUSR 可读 S_IWUSR 可写 S_IXUSR 可执行 S_IXRWU 可读可写可执行 除用以上宏来选择创建模式,也可以用数字来表示
-
-
打开
-
头文件
- #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参数可用来说明此函数的多个选择项
- 以下可选项可以同时指定0个或多个, 和必选项按位或起来作为flags参数。连接方式为管道符 |
- O_CREAT 若此文件不存在则创建它。使用此选择项时,需同时说明第三个参数mode,用其说明该新文件的存取权限。
- O_NONBLOCK如果pathname指的是一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式。
- O_TRUNC 打开文件长度截短为0,即清空
- mode对于open函数而言,仅当创建新文件时才使用第三个参数
- 即打开方式,定义在<fcntl.h>头文件
- O_RDONLY 只读打开
- O_WRONLY 只写打开
- O_RDWR 读、写打开
- O_APPEND 追加(只写)
- 返回值
- 成功返回新分配的文件描述符,
- 出错返回-1并设置errno
- 输出错误三方式
-
(1)errno就是error number,是由OS来维护的一个全局变量,任何OS内部函数都可以通过设置errno来告诉上层调用者究竟刚才发生了一个什么错误。
-
(2)perror()
-
用于将上一条语句(方法)执行后的错误打印到标准输出上。一般情况下(没有使用重定向的话),就是输出到控制台上。
#include <stdio.h> void perror(const char *s); //perror - print a system error message
-
- strerror()
-
streorror=string+error,就是将errno值翻译成描述错误类型的string语句!
#include <string.h>
char *strerror(int errnum); //strerror return string describing error number实例:
#include<stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h>//维护errno全局变量 #include <string.h>//strerror函数使用 int main(void) { int fd = -1; // fd 就是file descriptor,文件描述符 // 第一步:打开文件 fd = open("c.txt", O_RDWR); if (-1 == fd) { perror("文件打开错误"); printf("error num:%d\r\n",errno); printf("%s\n", strerror(errno)); _exit(-1); } else { printf("文件打开成功,fd = %d.\n", fd); } return 0; }
运行结果:
-
-
-
-
关闭
- int close(int fd)
- fd:文件描述符——对应open
- EOF(End Of File),通常在文本的最后存在此字符表示资料结束
- 在终端(黑框)中手动输入时,系统并不知道什么时候到达了所谓的“文件末尾”,因此需要用<Ctrl + z>组合键然后按 Enter 键的方式来告诉系统已经到了EOF,这样系统才会结束while.
- int close(int fd)
-
系统调用
-
读
- int read(int fd, const void *buf, size_t length)
- 功能:从文件描述符fd所指定的文件中读取length个字节到buf所指向的缓冲区中,返回值为实际读取的字节数。
- 返回
- -1👉出错
- =length👉输出
- 0< <length
- EOF👉返回0EOF的意义及用法(while(scanf("%d",&n) != EOF))_大C的博客-CSDN博客_eof
-
写
-
int write(int fd, const void * buf, size_t length)
-
功能:把length个字节从buf指向的缓冲区中写到文件描述符fd所指向的文件中,返回值为实际写入的字节数。
-
返回
- 当length为0时,返回0,除此之外不会返回0
- EOF👉不返回0
- 0< <length
- =length👉输出
- -1👉出错
-
-
定位
- int lseek(int fd, offset_t offset, int whence)
- 功能:将文件读写指针相对whence移动offset个字节。操作成功时,返回文件指针相对于文件头的位置
- offset
- 可取负值,表示向前移动。
- whence(可使用下述值)
- SEEK_SET:相对文件开头
- SEEK_CUR:相对文件读写指针的当前位置
- SEEK_END:相对文件末尾
- 例如下述调用 可将文件指针相对当前位置向前移动5个字节:
- lseek(fd, -5, SEEK_CUR)
- 利用lseek来计算文件长度
- lseek函数的返回值为文件指针相对于文件头的位置
- lseek(fd, 0, SEEK_END)
-
-
应用
-
复制文件(系统调用):实现文件复制_小羊咩噗的博客-CSDN博客
-
输出三个hello:输出三个hello_小羊咩噗的博客-CSDN博客
-
复制文件(库函数):数据库——文件复制_小羊咩噗的博客-CSDN博客
-
四、有缓冲访问文件(库函数)
C库函数的文件操作是独立于具体的操作系统平台的,不管是在DOS、Windows、Linux还是在VxWorks中都是这些函数。
-
创建和打开
- FILE *fopen(const char *filename, const char *mode)
- FILE:结构体
- filename:打开的文件名(包含路径,缺省为当前路径)
- mode:打开模式
- “r” :只读,文件必须已存在
- “w”:只写,如果文件不存在则创建,如果文件已存在则把文件长度截断(Truncate)为0字节再重新写,也就是替换掉原来的文件内容
- “a”:只能在文件末尾追加数据,如果文件不存在则创建
- 👆无加号
-
👇有加号
- “r+”:允许读和写,文件必须已存在
- “w+”:允讲读和写,如果文件不存在则创建,如果文件已存在则把文件长度截断为0字节再重新写
- “a+”:允许读和追加数据,如果文件不存在则创建
- b用于区分二进制文件和文本文件,这一点在DOS、Windows系统中是有区分的,Linux不区分二进制文件和文本文件,所以不需要"b".
-
读
- size_t fread(void *ptr, size_t size, size_t n, FILE* stream)
- 功能:从stream指向的文件中读取n个字段,每字段为size字节,并将读取的数据放入ptr所指的字符数组中,返回实际已读取的字段数(n)。
-
写
- size_t fwrite (const void *ptr, size_t size, size_t n,FILE *stream)
- 功能:从缓冲区ptr所指的数组中把n个字段写到stream指向的文件中,每个字段长为size个字节,返回实际写入的字段数
-
读字符
- int fgetc(FILE *stream) 从指定的文件中读一个字符
-
#include<stdio.h> main() { FILE *fp; char ch; if((fp=fopen("c1.txt","r+"))==NULL) { printf("\nCannot open file strike any key exit!"); /* getchar(); //无用,让显示终端暂停可看,待输入对应字符终端显示消失 */ exit(1); } ch=fgetc(fp); while(ch!=EOF) //取所有 { putchar(ch); ch=fgetc(fp); } fclose(fp);
-
写字符
- int fputc(int c, FILE *stream) 向指定的文件中写入一个字符
-
#include<stdio.h> main() { FILE *fp; char ch; if((fp=fopen("string","w+"))==NULL) { printf("Cannot open file,strike any key exit!"); getch(); exit(1); } printf("input a string:\n"); ch=getchar(); while (ch!='\n') { fputc(ch,fp); ch=getchar(); } printf("\n"); fclose(fp);
头文件,编程接口,编程接口对应函数……类型,用法,步骤
error对应数字什么错误
处理error编号的函数
本地存储
- 文件操作(系统调用、C库函数)
-
C标准库提供的读写文件的fread和fwrite函数:
FILE *fopen(char *filename, *type);
size_t fread( void *buffer, size_t size, size_t count, FILE *stream);
size_t fwrite( const void *buffer, size_t size, size_t count,FILE *stream);但是在学习UNIX / Linux环境时会发现操作系统提供的系统调用为:
int open(const char * filename, int flag, ...)
int read(int fildes, char * buf, off_t count);
int write(int fildes, const char * buf, off_t count);C语言作为一种跨平台、可移植的高级语言,其库函数想必是对操作系统的系统调用进行了一番封装,但是仔细比较这两组函数的参数就会发现,库函数的参数相对复杂一点,而且最大的区别在于用来操作文件的部分:FILE *stream和int fides...
库函数里用一个FILE*类型的指针来操作一个打开的文件,而系统调用则使用一个整数来表示一个打开的文件
-
- 数据库(数据库指令、C编程)
多任务
- 进程
- 创建方法:for、vfor;
- 等待wait;
- 退出qxit;
- 让当前进程执行新的任务exec;
- 进程间的通讯
- 管道通信
- 有名
- 无名
- 信号(唯一异步)
- 共享内存;(效率高)
- 消息队列;
- 管道通信
- 线程(同一进程)
- 创建(create)
- 退出(qxit)
- 等待(join)
- 同步(复制锁条件变量)
网络编程
- TCP——有链接、有协议、有先后
- 并发
- socket
- UDP
- 循环——线程节省内存空间