文章目录
标准库IO接口:
fread接口:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数解释:
ptr:用于接收数据的缓冲区
size:要读取的块大小
nmemb:被读取的块大小
stream:文件流指针
fseek接口:
int fseek(FILE *stream, long offset, int whence);
功能:对stream文件的读写位置跳转到从whence位置偏移offset个字节处
参数解释:
SEEk_SET 文件的起始位置
SEEK_CUR 当前读写位置
SEEK_END 文件末尾位置
offset偏移量
fseek(fp,0,SEEK_SET) 最后一定要记得fclose();
系统调用IO接口:
常用的接口:open write read lseek close
包含的头文件#include <fcntl.h>
open接口:
int open(const char *pathname, int flags, mode_t mode);
功能:打开文件
pathname:指定要打开的文件名称
flags:选项参数
必选参数:O_RDONLY, O_WRONLY, or O_RDWR 三个只能选择一个
可选参数:O_CREAT 若文件存在则打开,不存在就创建新文件
O_EXCL 与O_CREAT同时使用,若文件存在则报错,不存在则创建
O_TRUNC 打开文件同时截断文件为0长度
O_APPEND 写入数据总是写入末尾
返回值:文件描述符(正整数) 失败:-1
必须参数选择一个可以或上可选参数多个,满足多种需求
write接口:
ssize_t write(int fd, const void *buf, size_t count);
功能:写入数据
参数解释:
fd:open打开文件返回的文件描述符
buf:要写入的数据
count:要写入的字节数
返回值:实际写入的字节数 失败:-1
lseek接口:
off_t lseek(int fd, off_t offset, int whence);
功能:跳转fd的读写位置到指定位置
read接口:
ssize_t read(int fd, void *buf, size_t count);
返回值:返回实际读取到的字节数,失败返回-1
close接口:
int close(int fd);
功能:关闭文件
文件描述符:
正整数 sda:表示SATA的接口的第一块硬盘,第27块表示为sdaa
struct file是用数组来组织的 结构体指针数组
内核中文件描述信息结构体数组的下标
分配规则: 最小未使用 一个进程运行起来默认先打开三个文件
标准输入,标准输出,标准错误文件
0 1 2 int文件描述符
stdin stdout stdeeor File*文件流指针
Q:文件描述符和文件流指针的关系?
A:printf 向标准输出文件写入数据 FILE*fp-->_fileno 通过这个fileno找到文件描述符
重定向:
指的是文件描述符的重定向,文件描述符这个下标中的文件描述信息,从一个文件变成了另一个文件
这个时候用户通过文件流指针向文件写入数据的时候,文件描述符没变,但是描述符下标的文件描述信息已经改变
>>追加重定向 O_APPEND
> 清空重定向 O_TRUNC
int dup2(int oldfd, int newfd);
将oldfd描述符对应的描述信息,向newfd中拷贝一份,让newfd也指向oldfd所指向的文件,若newfd本身已经有打开文件,会先关闭这个文件,让newfd重定向到oldfd
minishell增加重定向功能:
思路分析:
<1>对输入的字符串进行检测,遇到>符号之前的,作为命令以及参数解析
<2>遇到>之后紧跟>即为追加重定向,只有一个>为清空重定向
<3>符号>之后的字符串是文件名称
<4>按照重定向的方式打开文件,然后使用dup2进行重定向
代码实现:
检测操作:
#include<stdio.h>
#include <unistd.h>
#include <string.h>
#include<ctype.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
while (1)
{
printf("[luzihan@TecentCloud]$");
fflush(stdout);
char tmp[1024] = { 0 };
scanf("%[^\n]%*c",tmp);
printf("%s\n", tmp);
char* ptr=tmp;
//用来判断是追加重定向还是清空重定向的标记
int _flag=0;
char* _file=NULL;
while(*ptr!='\0')
{
//遇到第一个>,说明前面的字符串是命令以及参数
//如果只有一个>,说明是清空重定向,更改标记为1
//加上\0使前面的字符串完整,可以解析
if(*ptr=='>')
{
*ptr='\0';
ptr++;
_flag=1;
//如果遇到第二个>,说明是追加重定向,更改标记
//同理,加上\0,使字符串完整可以获得解析
if(*ptr=='>')
{
*ptr='\0';
ptr++;
_flag=2;
}
//如果这时ptr是空字符,说明还没到文件名称,ptr继续往后走
while(isspace(*ptr)&&*ptr!='\0')
{
ptr++;
}
//ptr这时不为空字符且不为\0,开始读取文件名称
_file=ptr;
//ptr不是空字符继续往后读取,直到遇到空字符,读取完毕,手动添加\0
while(!isspace(*ptr)&&*ptr!='\0')
{
ptr++;
}
*ptr='\0';
}
//如果没有遇到>,就往后走,解析字符串
ptr++;
}
IO操作:
//创建子进程,进行程序替换
int pid = fork();
if (pid == 0)
{
int fd=1;
if(_flag==1)
{
fd=open(_file,O_CREAT|O_WRONLY|O_TRUNC,0664);
}
else if(_flag==2)
{
fd=open(_file,O_CREAT|O_WRONLY|O_APPEND,0664);
}
dup2(fd,1);
execvp(argv[0], argv);
//进程创建失败直接退出
exit(0);
}
代码运行测试图: