系统调用和API
在Linux系统中,为了保护内核空间,将程序的运行空间,分为内存空间和用户空间(内核态和用户态)它们在运行在不同的级别上,在逻辑上是相互隔离的,因此用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据和用户函数。操作系统为用户提供了两个接口:一个是用户编程接口API,用户利用这些操作命令来组织和控制任务的执行或管理计算机系统;另一个是系统调用,编程人员使用系统调用来请求操作系统提供服务。
系统调用并不是直接与程序员进行交互的,它仅仅是一个通过软中断机制向内核提交请求,以获得内核服务的接口。进行系统调用时,程序运行空间从用户空间进入内核空间,处理后再返回到用户空间。Linux系统调用部分,是非常精简的系统调用(只有250个左右),继承了Unix系统调用最基础的部分:进程控制、系统控制、内存管理、网络管理、socket控制、用户管理和进程间通信8个模块。
在Linux中,用户编程接口(API)遵循了Unix中最流行的应用编程界面标准POSIX标准。这些系统调用编程接口主要是通过c库(libc)来实现的。
对于Linux来说,所有文件和设备(设备也是文件)的操作,都使用文件描述符来进行。文件描述符是一个非负的整数,它是一个索引值,指向内核里每一个进程打开文件的记录表。当打开一个文件或者创建一个新文件,内核就会返回一个文件描述符,作为这个文件在用户空间的代表和唯一标识,读写函数等需要使用它。
通常,一个进程启动时,都会打开3个文件:标准输入、标准输出和标准出错处理。这三个文件对应的文件描述符为0、1、2 (即宏替换STDIN_FILENO、STDOUT_FILENO、STDERROR_FILENO)。使用这些宏替换,便于程序的理解和规范。
基本I/O操作:
Linux系统的读写函数,是不带缓冲区的读写操作。它们不属于ANSIC C的一部分,而是Unix的POSIX的一部分。
相关函数:
#include<sys/types.h>
#include<sys/stat.h> //声明mode_t
#include<fcntl.h> //声明调用open()时使用的flag常量
#include<unistd.h> //声明ssize_t
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
size_t write(int fd,const void *buf, size_t count);
size_t write(int fd,const void *buf, size_t count);
off_t lseek(int fd, off_t offset, int whence);
int close(int fd);
open函数:
pathname:文件名,相对绝对都可以
flags:为一个或多个标识,表示文件打开方式。
mode:文件的存取权限模式,同文件属性权限那个的8进制表达。当打开已有文件时,将忽略这个参数。
返回值:文件描述符,失败返回 -1
flags表如下:
只需要写/读的话,就只写/只读,也可以文件专用,每个文件只负责一个特定的用途,有利于提高文件的重复利用。
read和write函数:
fd:文件描述符
buf:也是内存的一个地区。read则是指定文本流目的地,write则是文本流来源地
count:指定读写的字节数
返回值:错误的话,返回 -1.正确的话,返回实际的读写字节数。
lseek函数(光标位置偏移函数):
fd:文件描述符
offset :偏移量,多少个字节
whence:从哪里开始偏移,有有以下可选:
——SEEK_SET 偏移量设置为offset字节。(这一个最有用吧)
——SEEK_CUR 偏移量设置为当前位置加上offset字节。
——SEEK_END 偏移量设置为文件大小加上偏移字节大小。
返回值: 成功,lseek()返回的结果是从文件开头的字节偏移位置。否则,返回-1并设置errno以指示错误。
close函数:
fd:文件描述符
返回值:成功返回0,否则返回 -1.
程序:
#include<sys/types.h>
#include<sys/stat.h> //声明mode_t
#include<fcntl.h> //声明调用open()时使用的flag常量
#include<unistd.h> //声明ssize_t
#include<stdio.h>
/*****
功能设计:
open一个不存在的文件,写入,再换一个绝对路径的文件 lseek函数要使用
读取,最后关闭
绝对、相对地址都可以写
append失败了
用char [] 最佳
*****/
int main()
{
int FileDesc = 0;
int Flag = 0;
//又可以测试了
// char * BufftoWrite = "this is a BufftoWrite\n";
char BufftoWrite[] = "this is a BufftoWrite\n";
char BuffertoRead[120];
//第三个参数需不需要加,待测试
//写阶段
//可以写到其他地址那里去
//FileDesc = open("/mnt/hgfs/2440/tem.txt",O_WRONLY|O_CREAT,00777);
//失败了,append不知道怎么搞
//FileDesc = open("/mnt/hgfs/2440/tem.txt",O_APPEND,00001);
FileDesc = open("temp.txt",O_WRONLY|O_CREAT,00001);
printf("-1\n");
if(FileDesc == -1){
printf("the FileDesc = -1\n");
return (-1);
}
printf("-2\n");
Flag = write(FileDesc,BufftoWrite,sizeof(BufftoWrite));
if(Flag == -1){
printf("writing fails\n");
return (-1);
}
printf("-3\n");
Flag = close(FileDesc);
if(Flag == -1){
printf("closing fails\n");
return (-1);
}
//读阶段
FileDesc = open("/mnt/hgfs/2440/tem.txt",O_RDONLY,00777);
FileDesc = open("temp.txt",O_RDONLY,00777);
if(FileDesc == -1){
printf("the FileDesc = -1\n");
return (-1);
}
Flag = read(FileDesc,BuffertoRead,sizeof(BuffertoRead));
if(Flag == -1){
printf("reading fails\n");
return (-1);
}
printf("%s\n",BuffertoRead);
//lseek阶段
Flag = lseek(FileDesc,5,SEEK_SET);
if(Flag == -1){
printf("lseeking fails\n");
return (-1);
}
Flag = read(FileDesc,BuffertoRead,sizeof(BuffertoRead));
if(Flag == -1){
printf("reading fails\n");
return (-1);
}
printf("%s\n",BuffertoRead);
Flag = close(FileDesc);
if(Flag == -1){
printf("closing fails\n");
return (-1);
}
return 0;
}