调用系统函数进行文件的读写
打开文件:
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中.