【Linux】系统文件接口
目录
一、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 else20 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 else20 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#系列的函数,都是对系统调用的封装,方便二次开发。
关于系统文件接口的内容就讲到这里,希望同学们多多支持,如果有不对的地方欢迎大佬指正,谢谢!