目录
前言
01 标准输入、标准输出和标准错误
02 打开文件 fopen()
03 新建文件的权限
04 fclose()关闭文件
05 读文件和写文件
06 库函数 fseek 定位
6.1 lseek的使用
07 ftell()函数
前言
🎬 个人主页:@ChenPi
🐻推荐专栏1: 《C++_@ChenPi的博客-CSDN博客》✨✨✨
🔥 推荐专栏2: 《Linux C应用编程(概念类)_@ChenPi的博客-CSDN博客》✨✨✨
🛸推荐专栏3: 《 链表_@ChenPi的博客-CSDN博客 》 ✨✨✨
🌺本篇简介 : 上一章我们学了系统调用,open,read,write,lseek等等,这章我们学习一下C库函数的open,read,write函数
在Linux环境下,个人平时还是使用系统调用多一些,但相对于说可移值性来说,还是C库函数好,
而且相关的API还会多些
01 标准输入、标准输出和标准错误
- 标准输入设备指的就是计 算机系统的标准的输入设备,通常指的是计算机所连接的键盘;
- 标准输出设备指的是计算机系统中用于 输出标准信息的设备,通常指的是计算机所连接的显示器
- 标准错误设备则指的是计算机系统中用于显示 错误信息的设备,通常也指的是显示器设备。
每个进程启动之后都会默认打开标准输入、标准输出以及标准错误,得到三个文件描述符
STDIN_FILENO 0 代表标准输入
STDOUT_FILENO 1 代表标准输出
STDERR_FILENO 2 代表标准错误
分别代表 0、1、2,这些宏定义在 unistd.h 头文件中:
/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */
0、1、2 这三个是文件描述符,只能用于文件 I/O(read()、write()等),那么在标准 I/O 中,自然是无 法使用文件描述符来对文件进行 I/O 操作的,它们需要围绕 FILE 类型指针来进行,在 stdio.h 头文件中有相 应的定义,如下:
/* Standard streams. */
extern struct _IO_FILE *stdin; /* Standard input stream. */
extern struct _IO_FILE *stdout; /* Standard output stream. */
extern struct _IO_FILE *stderr; /* Standard error output stream. */
/* C89/C99 say they're macros. Make them happy. */
#define stdin stdin
#define stdout stdout
#define stderr stderr
Tips:struct _IO_FILE 结构体就是 FILE 结构体,使用了 typedef 进行了重命名。
所以,在标准 I/O 中,可以使用 stdin、stdout、stderr 来表示标准输入、标准输出和标准错误。
02 打开文件 fopen()
在 0 所介绍的文件 I/O 中,使用 open()系统调用打开或创建文件
而在标准 I/O 中,我们将使用库函数fopen()打开或创建文件,fopen()函数原型如下所示:
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
函数参数和返回值含义如下:
- path:参数 path 指向文件路径,可以是绝对路径、也可以是相对路径。
- mode:参数 mode 指定了对该文件的读写权限,是一个字符串,稍后介绍。
- 返回值:调用成功返回一个指向 FILE 类型对象的指针(FILE *),该指针与打开或创建的文件相关联, 后续的标准 I/O 操作将围绕 FILE 指针进行。如果失败则返回 NULL,并设置 errno 以指示错误原因
参数 mode 字符串类型,可取值为如下值之一:
mode参数取值
- r 以只读方式打开文件。
- r+ 以可读、可写方式打开文件。
- w 以只写方式打开文件,如果参数 path 指定的文件 存在,将文件长度截断为 0;如果指定文件不存在 则创建该文件。
- w+ 以可读、可写方式打开文件,如果参数 path 指定 的文件存在,将文件长度截断为 0;如果指定文件 不存在则创建该文件。
- a 以只写方式打开文件,打开以进行追加内容(在 文件末尾写入),如果文件不存在则创建该文 件。
- a +以可读、可写方式打开文件,以追加方式写入 (在文件末尾写入),如果文件不存在则创建该 文件。
03 新建文件的权限
由 fopen()函数原型可知,fopen()只有两个参数 path 和 mode,
不同于 open()系统调用,它并没有任何一 个参数来指定新建文件的权限。
当参数 mode 取值为"w"、"w+"、"a"、"a+"之一时,如果参数 path 指定的文 件不存在
则会创建该文件,
那么新的文件的权限是如何确定的呢?
虽然调用 fopen()函数新建文件时无法手动指定文件的权限,但却有一个默认值:
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666)
使用示例
- 使用只读方式打开文件: fopen(path, "r");
- 使用可读、可写方式打开文件: fopen(path, "r+");
- 使用只写方式打开文件,并将文件长度截断为 0,如果文件不存在则创建该文件:fopen(path, "w");
04 fclose()关闭文件
调用 fclose()库函数可以关闭一个由 fopen()打开的文件,其函数原型如下所示:
#include <stdio.h>
int fclose(FILE *stream);
参数 stream 为 FILE 类型指针,调用成功返回 0;失败将返回 EOF(也就是-1),并且会设置 errno 来 指示错误原因。
05 读文件和写文件
fread()和 fwrite()库函数
对文件进行读、写操 作了,函数原型如下所示:
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
库函数 fread()
用于读取文件数据,其参数和返回值含义如下:
- ptr:fread()将读取到的数据存放在参数 ptr 指向的缓冲区中;
- size:fread()从文件读取 nmemb 个数据项,每一个数据项的大小为 size 个字节,所以总共读取的数据大 小为 nmemb * size 个字节。
- nmemb:参数 nmemb 指定了读取数据项的个数。
- stream:FILE 指针。
- 返回值:调用成功时返回读取到的数据项的数目(数据项数目并不等于实际读取的字节数,除非参数size 等于 1);
库函数 fwrite()
用于将数据写入到文件中,其参数和返回值含义如下:
- ptr:将参数 ptr 指向的缓冲区中的数据写入到文件中。
- size:参数 size 指定了每个数据项的字节大小,与 fread()函数的 size 参数意义相同。
- nmemb:参数 nmemb 指定了写入的数据项个数,与 fread()函数的 nmemb 参数意义相同。
- stream:FILE 指针。
- 返回值:调用成功时返回写入的数据项的数目(数据项数目并不等于实际写入的字节数,除非参数 size等于 1);如果发生错误,则 fwrite()返回的值将小于参数 nmemb(或者等于 0)。
由此可知,库函数 fread()、fwrite()中指定读取或写入数据大小的方式与系统调用 read()、write()不同, 前者通过 nmemb(数据项个数)*size(每个数据项的大小)的方式来指定数据大小,而后者则直接通过一 个 size 参数指定数据大小。
06 库函数 fseek 定位
库函数 fseek()则用于标准 I/O,其函数原型如下所示:
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
函数参数和返回值含义如下: stream:FILE 指针。
- offset:与 lseek()函数的 offset 参数意义相同。
- whence:与 lseek()函数的 whence 参数意义相同。
- 返回值:成功返回 0;发生错误将返回-1,并且会设置 errno 以指示错误原因;与 lseek()函数的返回值 意义不同,这里要注意!
调用库函数 fread()、fwrite()读写文件时,文件的读写位置偏移量会自动递增,使用 fseek()可手动设置 文件当前的读写位置偏移量。
6.1 lseek的使用
- 譬如将文件的读写位置移动到文件开头处: fseek(file, 0, SEEK_SET);
- 将文件的读写位置移动到文件末尾: fseek(file, 0, SEEK_END);
- 将文件的读写位置移动到 100 个字节偏移量处: fseek(file, 100, SEEK_SET);
fread,fwrite,fseek综合小案例
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp = NULL;
char rd_buf[100] = {0};
char wr_buf[] = "hello world";
int ret;
/* 打开文件 */
if (NULL == (fp = fopen("./test_file", "w+"))) {
perror("fopen error");
exit(-1);
}
printf("文件打开成功!\n");
/* 写文件 */
if (sizeof(wr_buf) >
fwrite(wr_buf, 1, sizeof(wr_buf), fp)) {
printf("fwrite error\n");
fclose(fp);
exit(-1);
}
printf("数据写入成功!\n");
/* 将读写位置移动到文件头部 */
if (0 > fseek(fp, 0, SEEK_SET)) {
perror("fseek error");
fclose(fp);
exit(-1);
}
/* 读文件 */
if (sizeof(wr_buf) >
(ret = fread(rd_buf, 1, sizeof(wr_buf), fp))) {
printf("fread error\n");
fclose(fp);
exit(-1);
}
printf("成功读取%d 个字节数据: %s\n", ret, rd_buf);
/* 关闭文件 */
fclose(fp);
exit(0);
}
07 ftell()函数
库函数 ftell()可用于获取文件当前的读写位置偏移量,其函数原型如下所示:
#include <stdio.h>
long ftell(FILE *stream);
参数 stream 指向对应的文件,函数调用成功将返回当前读写位置偏移量;调用失败将返回-1,并会设置errno 以指示错误原因。