Linux下,一切皆文件!
在Linux系统中,一切皆文件,不仅我们平时认为的文件是文件,而且显示器,键盘,磁盘…都是文件。当进程需要对某些文件进行操作时,就必须在进程中打开所要操作的对应文件。而一个进程的所有状态信息都会被保存在进程的task_struct(Linux下的进程PCB)中,在task_struct中,存在一个指针,它指向一个结构体file_struct,而在这个结构体中存在一个数组fd_array[],这个数组保存的都是当前进程打开的文件的文件指针。这个数组的下标,就是我们所述的文件描述符。
所以在进程中,只需要知道相应的文件所对应的下标,就可以找到对应的文件。
代码测试:
#include
#include
#include
#include
#include
int main()
{
int fd;
umask(0);//设置文件默认访问权限
fd = open("file", O_CWRONLY|O_CREAT,0644);
if(fd < 0)//打开文件失败
{
printf("打开文件失败!\n");
exit(-1);
}
printf("新文件的文件描述符 fd = %d\n", fd);
close(fd);//关闭文件
return 0;
}
程序结果:1
open接口介绍
#include
#inclUde
#include
int open(const char* pathname, int flags);
int open(const char* pathname, int flags, mode_t mode);
pathname:要打开或创建的文件
flags:打开文件时,可以传入多个参数选项,之间可以用“或”隔开,构成flags
O_RDONLY:只读打开
O_WRONLY:只写打开
O_RDWR:读,写打开
O_CREAT:若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND:追加写
返回值:
成功打开文件,返回新文件的文件描述符
失败返回-1
操作系统的标准输出是显示器,标准输入为键盘,输出/输入重定向的意思即就是将进程的标准输出/输入更改为用户自定义的文件。
常见的重定向有:>,<,这是操作系统提供给我们的重定向接口,当在shell命令行执行echo “hello world!” > file时,他会给当前路径下的file文件内写入"hello world!",不会在显示器上打印"hello world!"。
Linux操作系统下,一切皆文件,当我们想给显示器上打印"hello world!“时,操作系统会执行的操作就是给显示器这个文件中,写入"hello world!”,当发生输出重定向时,操作系统会首先关闭标准输出,这时,file_struct结构体中的文件描述符数组中下标为1的位置就会闲置,当下标为1的位置闲置时,打开另外一个文件,那么这个新文件所分配到的文件标识符就会是1,当其他进程要向标准输出打印数据时,就会将此时的新文件默认为标准输出,这样就实现了输入重定向。
#include
int close(int fd);
fd:文件描述符
返回值:
成功返回0
失败返回-1
代码实现
#include
#include
#include
#include
#include
int main()
{
int fd;
int close_right = -1;//默认关闭失败
close_right = close(1);//关闭标准输出stdout
if(close_right == -1)//关闭失败
{
exit(-1);
}
umask(0);
fd = open("file", O_WRONLY|O_CREAT,0644);
if(fd == -1)
{
exit(-1);
}
printf("hello world!\n");//向标准输入写入hello world!
close(fd);
return 0;
}
程序结果:向file文件中写入"hello world!"
FILE是C库提供的一个结构体,用来操作文件,因为IO相关函数与系统调用接口对应,而且库函数封装了系统调用,所以本质上,访问文件都是通过文件的文件描述符fd访问的,所以在C库提供的结构体FILE中,一定封装了文件描述符fd。
存储一个文件,既要存储文件的数据信息,也要存储文件的属性信息。
电脑的磁盘是由盘片组成的,一个盘片有两个柱面,两个柱面都可以存储信息,每个柱面由很多同心圆组成,在每一个同心圆上有很多扇区(使用缺口分割),数据即存储在这些同心圆上,这样的一个圆叫做磁道,我们可以将它理解为线性结构,将整个磁盘分成很多个小块来管理,这样的操作叫做磁盘分区。
代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_ARGV 20
#define MAX_CMD 1024
int cmd_cut(char cmd[], char* argv[])//发生重定向则返回重定向符号所在位置
{
char* buf = " ";
int i = 0;
int stdout_off = 0;
char stdout_file_name[50];
argv[i++] = strtok(cmd, buf);
while(argv[i++]=strtok(NULL, buf))
{
if(*argv[i-1]=='>'||
*argv[i-1]=='<'||
*argv[i-1]=='&')
{
//记录重定向符号位置
stdout_off = i - 1;
}
}
//处理末尾输入的'\n'
argv[i - 1] = NULL;
if(*argv[i - 2] == '\n')
{
argv[i - 2] = NULL;
}
else
{
char* p = (argv[i-2] + strlen(argv[i-2]) - 1);
*p = '\0';
}
//判断是否发生重定向
if(stdout_off != 0)
{
return stdout_off;
}
return 0;
}
int which_redirect(char* argv[], const int redirect)
{
char stdout_file_name[50];
if(redirect != 0)
{
strcpy(stdout_file_name, argv[redirect+1]);//保存输出/输入文件名
if(*argv[redirect] == '>')//输出重定向
{
argv[redirect] = NULL;
close(1);
return open(stdout_file_name, O_WRONLY|O_CREAT);
}
else if(*argv[redirect] == '<')//输入重定向
{
argv[redirect] = NULL;
close(0);
return open(stdout_file_name, O_WRONLY|O_CREAT);
}
else if(*argv[redirect] == '&')
{
argv[redirect] = NULL;
close(1);
}
else
{
printf("重定向标识符错误!\n");
exit(0);
}
}
return -1;
}
//新进程
void new_pro(char* argv[], const int redirect)
{
pid_t id=fork();
char stdout_file_name[20];
int fd = -1;
if(-1==id)
{
perror("fork");
exit(-1);
}
else if(0==id)//子进程
{
fd = which_redirect(argv,redirect);//判断输出/输入/不发生重定向 并处理
execvp(argv[0],argv);
}
else//父进程
{
int st;
while(wait(&st)!=id);
}
}
int main()
{
char cmd[MAX_CMD]={'\0'};
char* argv[MAX_ARGV];
int redirect = 0;//重定向标识符 默认不发生重定向
while(1)
{
printf("[ahao@AHAOAHA ~ ]& ");
fgets(cmd,sizeof(cmd),stdin);
redirect = cmd_cut(cmd,argv);
new_pro(argv, redirect);
}
close(1);
return 0;
}
gcc -c [要生成静态库的代码文件名] -o [指定生成文件名.o]
ar -rc [lib静态库名称.a] [*.o]
ar是gnu归档工具
rc表示(replace and create)
ar -tv [静态库文件名] :查看静态库中的目录列表
t(列出静态库中的文件)
v(详细信息)
gcc -fPIC -c [要生成静态库的代码文件名]
fPIC:产生位置无关码(position independent code)
gcc -shared -o [lib动态库名称.so] [*.o]
shared:表示生成共享库格式
gcc [要编译的文件名] -o [指定可执行文件名] -L[动态库所在路径] -l[动态库名]
l :链接动态库,只要库名即可
L :动态库所在路径