目录
一、C文件接口
1、fopen
2、fprintf
3、snprintf
二、系统文件IO
1、open
2、write
3、read
4、C文件接口与系统文件IO的关系
一、C文件接口
1、fopen
FILE *fopen(const char *path, const char *mode);
fopen 函数返回值类型为 FILE 。参数列表中, path 为文件路径, mode 为打开方式。
打开文件的方式有如下几种:
r | 打开文本文件进行阅读。 流位于文件的开头。 |
r+ | 开放读和写。 流位于文件的开头。 |
w | 打开文件进行写入。如果文件不存在,则创建该文件,否则文件被清空。 流位于文件的开头。 |
w+ | 开放读和写。如果文件不存在,则创建该文件,否则文件被清空。 流位于文件的开头。 |
a | 打开以追加(在文件末尾写入)。 如果文件不存在,则创建该文件。 流位于文件的末尾。 |
a+ | 打开以进行读取和追加(在文件末尾写入)。 如果文件不存在,则创建该文件。用于读取的初始文件位置位于文件的开头, 但输出始终附加到文件末尾。 |
2、fprintf
int fprintf(FILE *stream, const char *format, ...);
与 printf 不同, printf 默认向显示器打印消息,而 fprintf 则可以指定文件流,向指定文件打印。
编写如下代码:
1 #include <stdio.h>
2
3 #define LOG "log.txt"
4
5 int main()
6 {
7 FILE* fp = fopen(LOG, "w");
8 if(fp == NULL)
9 {
10 perror("fopen");
11 return 1;
12 }
13
14 const char* msg = "hello world";
15 int cnt = 5;
16 while(cnt)
17 {
18 fprintf(fp, "%s: %d: ljb\n", msg, cnt);
19 //fputs(msg, fp);
20 cnt--;
21 }
22
23 fclose(fp);
24 return 0;
25 }
运行观察结果:
也可以使用 fprintf 函数向显示器文件里打印,以实现和 printf 函数相同的效果:
3、snprintf
int snprintf(char *str, size_t size, const char *format, ...);
snprintf 函数可以把内容打印到缓冲区里,并且通过设置参数 size 控制打印的长度。
编写如下代码:
1 #include <stdio.h>
2
3 #define LOG "log.txt"
4
5 int main()
6 {
7 FILE* fp = fopen(LOG, "w");
8 if(fp == NULL)
9 {
10 perror("fopen");
11 return 1;
12 }
13
14 const char* msg = "hello world";
15 int cnt = 5;
16 while(cnt)
17 {
18 char buffer[256];
19 snprintf(buffer, sizeof(buffer), "%s: %d:ljb\n", msg, cnt);
20 printf("%s", buffer);
21 }
22
23 fclose(fp);
24 return 0;
25 }
运行观察结果:
二、系统文件IO
1、open
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
open 函数参数列表中, pathname 为文件路径与文件名, flags 为要打开文件的选项(以位图形式传递), mode 为打开文件的权限。返回值为文件描述符。
flags参数:
- O_RDONLY:只读打开
- O_WRONLY:只写打开
- O_RDWR:读,写打开
- O_CREAT:若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
- O_APPEND:追加写(需要配合O_WRONLY使用)
- O_TRUNC:将文件清空
返回值:
- 成功:新打开的文件描述符
- 失败:-1
编写如下代码:
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <string.h>
8
9 #define LOG "log.txt"
10
11 int main()
12 {
13 umask(0);
14 int fd = open(LOG, O_CREAT | O_WRONLY, 0666);
15 if(fd == -1)
16 {
17 printf("fd: %d, error: %d, errstring: %s\n", fd, errno, strerror(errno));
18 }
19
20 else
21 printf("fd: %d, error: %d, errstring: %s\n", fd, errno, strerror(errno));
22
23 close(fd);
24
25 return 0;
26 }
其中 O_CREAT 与 O_WRONLY 为宏定义,传递参数 flags 。 O_CREAT 为如果文件不存在,则自动创建该文件。 O_WRONLY 为以只读模式打开文件。需要注意的是,他们不会对原始文件内容做清空,下一次写入时,虽然还是从开头开始写,但是原本的内容没被覆盖的部分仍然会残留。
运行观察结果:
如图所示,打开文件所返回的文件描述符是 3 。
刚刚被创建的 log.txt 文件的权限为 666 。
2、write
ssize_t write(int fd, const void *buf, size_t count);
write 函数的参数列表中, buf 为缓冲区首地址, count 为本次读取,期望写入多少个字节的数
据。 返回值:实际写了多少字节数据。
编写如下代码:
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <string.h>
8
9 #define LOG "log.txt"
10
11 int main()
12 {
13 umask(0);
14 int fd = open(LOG, O_CREAT | O_WRONLY, 0666);
15 if(fd == -1)
16 {
17 printf("fd: %d, error: %d, errstring: %s\n", fd, errno, strerror(errno));
18 }
19 else
20 printf("fd: %d, error: %d, errstring: %s\n", fd, errno, strerror(errno));
21
22 const char* msg = "hello world";
23 int cnt = 5;
24 while(cnt)
25 {
26 char line[128];
27 snprintf(line, sizeof(line), "%s, %d\n", msg, cnt);
28
29 write(fd, line, strlen(line));
30 cnt--;
31 }
32
33 close(fd);
34
35 return 0;
36 }
需要注意的是,这里的数据字节数使用的是 strlen(line) ,而不是 strlen(line) + 1 。这是因为字符串最后一定要加 '\0' 是C语言的规定,而不是文件的规定。
3、read
ssize_t read(int fd, void *buf, size_t count);
read 函数的参数列表中, buf 为缓冲区首地址, count 为本次读取,期望读取多少个字节的数
据。 返回值:实际读取了多少字节数据。
编写如下代码:
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <string.h>
8
9 #define LOG "log.txt"
10
11 int main()
12 {
13 umask(0);
14 int fd = open(LOG, O_RDONLY);
15 if(fd == -1)
16 {
17 printf("fd: %d, error: %d, errstring: %s\n", fd, errno, strerror(errno));
18 }
19 else
20 printf("fd: %d, error: %d, errstring: %s\n", fd, errno, strerror(errno));
21
22 char buffer[1024];
23
24 ssize_t n = read(fd, buffer, sizeof(buffer) - 1);
25 if(n > 0)
26 {
27 buffer[n] = '\0';
28 printf("%s\n", buffer);
29 }
30
31 close(fd);
32
33 return 0;
34 }
使用系统接口来进行IO的时候,一定要注意 '\0' 的问题。
运行观察结果:
4、C文件接口与系统文件IO的关系
fopen、fclose、fwrite、fputs、fread、fgets 都是C标准库当中的函数,我们称之为库函数(libc)。
open、close、write、read都属于系统提供的接口,称之为系统调用接口。
可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发。
关于系统文件接口的内容就讲到这里,希望同学们多多支持,如果有不对的地方欢迎大佬指正,谢谢!