文件的读写使用,重定向,文件描述符

调用系统函数进行文件的读写

打开文件:
int open(const char* pathname,int flags);
int open(const char* pathname,int flags,mode_t mode); //mode:当打开的文件不存在时,就要在打开文件的同时并创建文件,那么就需要设定文件的权限.
flags:打开文件的选项:若同时需要多种操作时,就可以将多个选项进行或运算.
O_WRONLY:只写打开
O_RDONLY:只读打开
O_RDWR:读写打开
O_CREAT:创建
写文件:
ssize_t write(int fd, const void *buf, size_t count);
若写入成功,返回写入的字节数.
若失败,返回-1.
返回0:对于普通文件没什么影响,而对于特殊文件有影响.
读文件:
ssize_t read(int fd, void *buf, size_t count);
若返回值大于零表示读取成功,并且返回值就是读取的字节数.
若返回值等于0,表示文件已经读完(当读一个空文件时就会返回0).
若返回值小于0,表示文件读失败.

下面是一个简单的例子:先写入文件,再从文件中读取.

  1 #include<stdio.h>                                                                                                      
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<sys/stat.h>
  5 #include<fcntl.h>
  6 #include<string.h>
  7 
  8 int main()
  9 {
 10     int fd = open("text.txt",O_WRONLY|O_CREAT,0666);  
 11     if(fd == -1)
 12     {
 13         perror("open");
 14         return 1;
 15     }
 16     const char* str = "You are breautiful.\n";
 17     int count = 5;
 18     while(count--)
 19     {
 20         write(fd,str,strlen(str));
 21     }
 22     close(fd);
 23     fd = open("text.txt",O_RDONLY);
 24     if(fd == -1)
 25     {
 26         perror("open");
 27         return 1;
 28     }
 29     char buf[1024] = {0};
 30     ssize_t size = read(fd,buf,sizeof(buf) - 1);
 31     if(size == 0)
 32     {
 33         //读到了文件结束
 34         return 0;
 35     }
 36     else if(size > 0)
 37     {
 38         //读成功
 39         buf[size] = '\0';
 40         printf("%s\n",buf);
 41     }
 42     else
 43     {
 44         //读失败
 45         return 1;
 46     }
 47     close(fd);
 48 }

文件描述符

结论:在Linux中,每个进程都会默认打开3个文件:标准输入(0),标准输出(1),标准错误(2).
标准输入:一般指物理设备的键盘
标准输出:一般指物理设备的显示器
标准错误:也是显示器

文件描述符:是指针数组的下标(从0开始).当我们打开一个文件时,操作系统就会在内存中创建对应的数据结构来描述目标文件(即我们打开的那个文件).该数据结构就是file结构体.当执行open()系统调用函数时,进程就会与文件连接起来.每一个进程都有一个指针*file,该指针指向一张表files_struct,该表中包含一个指针数组,数组中的每一个元素都是一个指向打开文件的指针.文件描述符就是这个指着数组的下表,所以通过文件描述符(数组下表)就可以找到对应的文件.
这里写图片描述
例如:可以直接通过文件描述符来输入输出

126     char buf[1024] = {0};
127     ssize_t s = read(0,buf,sizeof(buf));    //从标准输入读进来
128     if(s > 0)
129     {
130         buf[s] = 0;
131         write(1,buf,strlen(buf));      //写到标准输出
132         write(2,buf,strlen(buf));      //写到标准错误                                                                                
133     }

文件描述符的分配原则:

结论:从第一个未被占用的下标开始分配.
例如:

112     close(1);                                                                                                          
113     int fd = open("file",O_WRONLY|O_CREAT,0644);
114     if(fd == -1)
115     {
116         perror("open");
117         return 1;
118     }   
119     int count = 6;
120     while(count--)
121     {
122         printf("hello\n");   //本来应该输出到显数器,可是关闭了标准输出后,而又打开了一个新文件,所以新文件的文件描述符为1(就是关闭了的标准输出的文件描述符,那么此时就会打印到新文件之中)
123         fflush(stdout);
124     }   

结果:在新文件”file”中,有6行hello.
这里写图片描述
可以通过下面这个图来详细的解释上述的现象:
这里写图片描述
即:新打开的文件的文件描述符是1,而1又是标准输出的文件描述符,所以就会输出在文件描述符为1的file文件之中了.这其实是一种简单的重定向.

C语言中的FILE与文件描述符的区别

C语言中的FILE,是一个结构体,而该结构体的内部封装了文件描述符fd.
首先,我们回忆一下FILE的使用:

 10     FILE* fp = fopen("file.txt","w");
 11     if(fp == NULL)
 12     {
 13         return 1;
 14     }
 15     const char* str = "You are great!\n";
 16     int count = 5;
 17     while(count--)
 18     {
 19         fwrite(str,strlen(str),1,fp);
 20     }
 21     fclose(fp);
 22     fp = fopen("file.txt","r");
 23     if(fp == NULL)
 24     {
 25         return 1;
 26     }
 27     char buf[1024] = {0};
 28     ssize_t size = fread(buf,1,sizeof(buf) - 1,fp);
 29     if(size > 0)
 30     {
 31         buf[size] = '\0';
 32         printf("%s\n",buf);
 33     }
 34     else if(feof(fp))      
 35     {
 36         return 0;
 37     }
 38     fclose(fp);

这里写图片描述
1.打开文件
2.写文件
3.关闭文件
4.重新打开文件
5.读文件
6.关闭文件

feof与EOF的区别:
EOF(end of file):其实就是一个宏,文件结束的标志.在文件的内部就有一个EOF,就是-1,当文件读到-1时,就表示文件读完了.类比:字符串中的’\0’.只可以用来判断文本文件是否结束.
feof:同样也可以用来判断文件是否结束,但是feof()是一个函数.若文件已经结束,就返回1,否则返回0.既可以来判断文本文件的结束,也可以判断二进制文件的结束.

重定向

常见的重定向有:>(输出重定向) , >>(追加重定向) ,<(输入重定向).
在Linux中,可以这样简单的使用:

[huhu@localhost LinuxFile]$ ls > aa  //将ls执行的结果放到aa文件中
[huhu@localhost LinuxFile]$ echo "Me" > aa  //将Me追加到aa这个文件中
[huhu@localhost LinuxFile]$ ls aaaaa 2> aa //将错误信息重定向到AA文件中
[huhu@localhost LinuxFile]$ ls &>aa  //无论对错都将信息打印到aa文件中
[huhu@localhost LinuxFile]$ wc -l < aa   //输入重定向,将aa文件中的行号打印出来

在操作系统内部,有函数可以实现重定向.

int dup(int oldfd);
int dup2(int oldfd, int newfd);
int dup3(int oldfd, int newfd, int flags);

一般经常使用的是第二个函数.将newfd重定向到oldfd中.

猜你喜欢

转载自blog.csdn.net/Yinghuhu333333/article/details/80367028