基础IO—01
1.标准库的IO接口
标准库的IO接口有:fopen/fwrite/fread/fseek/fclose
FILE* fopen(char* filename, char* mode);//(文件名称,打开方式)
打开方式:r只读/r+读写/w只写/w+只读/a追加写/a+追加读写/b二进制操作
r+和w+的区别:r+读写打开文件,若文件不存在则报错/w+读写打开文件,若不存在文件则创建,若存在则清空原有文件内容。
b默认清空文件内容。如果不指定b则认为文件是文本操作,加上b则认为是二进制操作。
a不仅仅是追加写,如果文件不存在还会创建新文件。
返回值:成功返回一个FILE*的文件流指针,失败则返回NULL。
size_t fread(char* buf, size_t block_size, size_t block_count, FILE* fp);
//(缓冲区,块大小,快个数,文件流指针)
size_t fwrite(char* data, size_t block_size, size_t block_count, FILE* fp);
//(数据首地址,块大小,快个数,文件流指针)
fread/fwrite操作的数据实际大小为块大小*块个数。
返回值:返回实际操作的块个数。
fread/fwrite推荐块大小为1,快个数是想要操作的数据长度。
int fseek(FILE* fp, long offset, int whence);//将文件从whence位置偏移offset个字节
int fclose(FILE* fp);//关闭文件流指针,释放资源
fseek:文件没有数据也可以跳转读写位置。
#include<stdio.h>
#include<string.h>
int main()
{
FILE* fp = fopen("./test.txt", "r+");
//fseek(fp, 0, SEEK_SET);
fseek(fp, 0, SEEK_END);
char* ptr = "hello siwei\n";
int ret = fwrite(ptr, strlen(ptr), 1, fp);
printf("%d\n",ret);
fseek(fp, 0, SEEK_SET);
char buf[1024] = {0};
ret = fread(buf, 1, 1023, fp);
printf("%d\n",ret);
printf("%s\n", buf);
fclose(fp);
return 0;
}
2.系统调用IO接口
系统调用的IO接口有:open/read/write/lseek/colse
int open(char* filename, int flag, mode_t mode);
filename:想要打开的文件名称。
flag:选项参数–文件的打开方式。有必选项和可选项两种。
必选项:O_RDONLY-只读 O_WRONLY-只写 O_RDWR-读写
可选项:O_CREAT-文件存在则打开,不存在则创建。O_EXCL与O_CREAT同时使用,文件存在则报错,不存在则创建。O_TRUNC-打开文件的同时清空原有内容。O_APPEND-追加写。
mode:权限–如果使用了O_CREAT有可能创建新文件,就一定要指定文件权限,八进制数字形式。
返回值:成功返回一个非负整数—文件描述符—文件操作句柄;失败返回-1。
size_t write(int fd, char* data, size_t count);
fd:open返回的文件描述符—文件操作句柄。
data:要写入文件的数据的空间首地址。
count:要写入的数据大小。
返回值:成功返回实际写入文件的数据字节长度;失败返回-1。
size_t read(int fd, char* buf, size_t len);
fd:open返回的文件描述符—文件操作句柄。
buf:从文件中读取数据放到那块缓冲区的首地址。
len:想要读取的长度,len的长度不能大于缓冲区的大小。
返回值:成功返回的是实际读取到的数据字节长度;失败返回-1。
size_t lseek(int fd, long offset, int whence);
fd:open返回的文件描述符—文件操作句柄。
offset:偏移量。
whence:从哪里开始偏移。SEEK_SET-文件起始位置,SEEK_CUR-文件当前读写位置,SEEK_END-文件末尾。
返回值:成功返回当前位置对于起始位置的偏移量;失败返回-1。
int close(int fd);
通过文件描述符关闭文件,释放资源。
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main()
{
int fd = open("./test.txt", O_RDWR|O_CREAT, 0777);
lseek(fd, 0, SEEK_END);
char* ptr = "hello world\n";
int ret = write(fd, ptr, strlen(ptr));
printf("ret = %d\n", ret);
lseek(fd, 0, SEEK_SET);
char buf[1024] = {0};
ret = read(fd, buf, 1024);
printf("ret = %d\n%s\n", ret, buf);
close(fd);
return 0;
}
3.文件描述符
文件描述符起始就是内核中一个进程打开的文件描述信息表的下标,通过这个下标可以在内核中找到相应的文件描述信息,通过这个描述信息可以实现文件的操作。
如果打开了一个文件,对于这个文件操作完成后一定要关闭,释放资源。因为文件描述符实际是有限的,若不关闭文件,文件描述符用光,则在进程中就打不开新文件了。
一个程序运行起来在进程中会默认打开三个文件:标准输入-0-stdin/标准输出-1-stdout/标准错误-2-stderr。
文件描述符的分配规则:最小未使用规则。分配文件描述信息表中,文件描述符最小且没有使用的。
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
int main()
{
close(1);
umask(0);
int fd = open("./test.txt", O_RDWR|O_CREAT, 0664);
printf("fd = %d\n", fd);
fflush(stdout);
close(fd);
}
printf打印数据到标准输出中,如果关闭了标准输出1,打开新的文件后,按照文件描述符的分配规则。这个新打开的文件描述符就是1,所以在这个程序中printf并没有将数据打印出来,而是在刷新缓冲区之后,将数据写入到了文件中。
4.重定向
重定向:将数据不再写入原本的文件,而是写入新的指定的文件中—实现方式就是替换这个描述符对应的文件描述信息,实际上是描述符的重定向,改变描述符所指向的文件,就改变了数据的流向。>清空重定向,>>追加重定向。
int dup2(int oldfd, int newfd);//描述符重定向函数
让newfd这个描述符也指向oldfd所指向的文件,这时候oldfd和newfd都能够操作oldfd所指向的文件。
在minishell中实现>/>>标准输出重定向:
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
umask(0);
while(1)
{
printf("[sw@minishell]$ ");
fflush(stdout);//刷新标准输出缓冲区i
char buf[1024] = {0};
fgets(buf, 1023, stdin);
buf[strlen(buf) - 1] = '\0';
char* ptr = buf;
int flag = 0;
char* file = NULL;
while(*ptr != '\0')
{
if(*ptr == '>')
{
flag = 1;
*ptr = '\0';
ptr++;
if(*ptr == '>')
{
flag = 2;
ptr++;
}
while(*ptr == ' ' && *ptr != '\0')ptr++;
file = ptr;
while(*ptr != ' ' && *ptr != '\0')ptr++;
*ptr = '\0';
}
ptr++;
}
char* argv[32] = {NULL};
int argc = 0;
ptr = buf;
while(*ptr != '\0')
{
if(*ptr != ' ')
{
argv[argc] = ptr;
argc++;
while(*ptr !=' ' && *ptr != '\0')
{
ptr++;
}
*ptr = '\0';
}
ptr++;
}
argv[argc] = NULL;
pid_t pid = fork();
if(pid == 0)
{
if(flag == 1)
{
int fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0777);
dup2(fd, 1);
}
else if(flag == 2)
{
int fd = open(file, O_WRONLY|O_CREAT|O_APPEND, 0777);
dup2(fd, 1);
}
execvp(argv[0], argv);
exit(0);
}
wait(NULL);
}
return 0;
}