上篇博客介绍了文件的基本知识,本文将详细讲解有关文件顺序读写和随机读写函数。
一、文件的顺序读写
在C语言中,文件的顺序读写指的是按照文件中的顺序来读取或写入数据,下面是常用到的函数。
功能 | 函数名 | 适用于 |
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
1.1 fgetc()和fputc()函数
fgetc
和 fputc
函数分别用于从文件中读取一个字符和向文件中写入一个字符。这两个函数都是标准I/O库中的一部分,提供了对文件字符级操作的能力。
1.1.1 fgetc()
int fgetc( FILE *stream );
fgetc
函数用于从指定的文件流中读取下一个字符(一个无符号字符),并将其作为 int
类型的值返回。如果到达文件末尾(EOF)或发生错误,则返回 EOF
。注意,EOF
是一个在 <stdio.h>
中定义的宏,通常是一个负值,用于指示文件结束或读取错误。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("text.txt", "r");//打开已经创建好的文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
int ret = fgetc(pf);
printf("%c\n", ret);
ret = fgetc(pf);
printf("%c\n", ret);
ret = fgetc(pf);
printf("%c\n", ret);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
1.1.2 fputc()
int fputc( int c, FILE *stream );
fputc
函数用于将一个字符写入到指定的文件流中。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fputc('f', pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
1.2 fgets()和fputs()函数
1.2.1 fputs()
int fputs( const char *string, FILE *stream );
fputs
函数用于将字符串写入到指定的文件流中,但不包括空字符 \0
。如果成功,它返回非负值;如果发生错误,则返回 EOF
。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件-行
fputs("abcde\n", pf);
fputs("fgh\n", pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
1.2.2 fgets()
fgets
函数用于从指定的文件流中读取一行文本(包括换行符,如果有的话,但最多读取到数组大小减一的位置),并将其存储在字符串中。如果成功,它会返回一个指向该字符串的指针;如果发生错误或到达文件末尾(EOF)而没有读取任何字符,则返回 NULL
。
char *fgets( char *string, int n, FILE *stream );
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
char arr[10] = { 0 };
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fgets(arr, 4, pf);
printf("%s\n", arr);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
1.3 fprintf()和fscanf()函数
1.3.1 fprintf()
fprintf
函数用于向指定的输出流(如文件)写入格式化的数据。
int fprintf( FILE *stream, const char *format [, argument ]...);
stream
是指向 FILE
对象的指针,该对象标识了要写入数据的输出流。
format
是一个格式字符串,指定了后续参数(...)如何写入到输出流中。这个格式字符串与 printf
函数的格式字符串非常相似。
后续参数(...)是要写入输出流的数据。
fprintf
函数返回写入的字符数(不包括终止的空字符),如果发生错误,则返回负数。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
char arr[10];
int num;
float sc;
};
int main()
{
struct S s = { "abcde",10,5.5f };
//对格式化的数据进行写文件
FILE *pf= fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fprintf(pf, "%s %d %f", s.arr, s.num, s.sc);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
1.3.2 fscanf()
fscanf
函数用于从指定的输入流(如文件)中按照指定格式读取数据。
int fscanf( FILE *stream, const char *format [, argument ]... );
stream
是指向 FILE
对象的指针,该对象标识了要从中读取数据的输入流。
format
是一个格式字符串,指定了后续参数(...)的读取方式。这个格式字符串与 scanf
函数的格式字符串非常相似。
后续参数(...)是指向变量的指针,这些变量用来存储从输入流中读取的数据。
fscanf
函数返回成功读取的项目数,如果到达文件末尾或发生读取错误,则返回 EOF
。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
char arr[10];
int num;
float sc;
};
int main()
{
struct S s = {0};
//对格式化的数据进行读文件
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fscanf(pf, "%s %d %f", s.arr, &(s.num ), &(s.sc));
//打印
printf("%s %d %f\n", s.arr, s.num, s.sc);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
1.4 fread()和fwrite()函数
1.4.1 fwrite()
fwrite
函数用于向文件写入数据块。
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
buffer
指向要写入的数据块的指针。
size
是每个数据项的大小(以字节为单位)。
count
是数据项的数量。
stream
是指向 FILE
对象的指针,该对象标识了要写入数据的输出流。
fwrite
返回成功写入的项数,如果发生错误,则返回小于count的值。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
char arr[10];
int num;
float sc;
};
int main()
{
struct S s = { "abc",10,5.5f };
//二进制的形式写
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fwrite(&s, sizeof(struct S), 1, pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
由于是以二进制的形式写入的,所以看不懂很正常。
1.4.2 fread()
fread
函数用于从文件流中读取数据。这个函数可以非常灵活地从文件中读取指定数量的元素,每个元素具有指定的大小(以字节为单位)。这使得 fread
成为处理二进制文件或需要精确控制读取数据量时非常有用的工具。
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
void *buffer
:指向一个数组的指针,该数组用于存储从文件读取的数据。
size_t size
:每个数据项的大小,以字节为单位。
size_t count
:要读取的数据项的最大数量。
FILE *stream
:指向 FILE
对象的指针,该对象标识了要从中读取数据的输入流。
成功时,fread
返回实际读取的元素数量,这可能会少于请求的数量(例如,如果到达文件末尾或发生错误)。
如果发生错误或到达文件末尾而没有读取任何数据,则返回 0
。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
char arr[10];
int num;
float sc;
};
int main()
{
struct S s = {0};
//二进制的形式读
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
fread(&s, sizeof(struct S), 1, pf);
//打印
printf("%s %d %f\n", s.arr, s.num, s.sc);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
二、 几种函数对比
2.1 函数
scanf:针对标准输入的格式化的输入语句
fscanf:针对所有输入流的格式化的输入语句
sscanf:从一个字符串中读取一个格式化的数据
printf:针对标准输出的格式化的输出语句
fprintf:针对所有输出流的格式化的输出语句
sprintf:把一个格式化的数据转换成字符串
以下是sscanf和sprintf函数的函数原型:
int sscanf( const char *buffer, const char *format [, argument ] ... );
int sprintf( char *buffer, const char *format [, argument] ... );
2.2 代码示例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
char arr[10];
int age;
float f;
};
int main()
{
struct S s = { "hello",20,5.5f };
struct S temp = { 0 };
char buf[100] = { 0 };
//sprintf 把一个格式化的数据转换成字符串
sprintf(buf, "%s %d %f", s.arr, s.age, s.f);
printf("%s\n", buf);
//从buf字符串中还原出一个结构体数据
sscanf(buf, "%s %d %f", temp.arr, &temp.age, &temp.f);
printf("%s %d %f\n", temp.arr, temp.age, temp.f);
return 0;
}
三、文件的随机读写
在C语言中,进行随机读写操作(即不是顺序地从文件开头或结尾读写,而是根据文件内的特定位置进行读写)时,主要依赖几个标准的文件操作函数,特别是那些允许你移动文件指针到文件中的特定位置的函数。
3.1 fseek()
fseek()
函数用于将文件内的位置指示器(即文件指针)移动到指定的位置。
int fseek( FILE *stream, long offset, int origin );
stream
是指向 FILE
对象的指针,该对象标识了要操作的文件。
offset
是从 whence
指定的位置开始计算的偏移量,以字节为单位。
origin是起始位置,可以是 SEEK_SET
(文件开头),SEEK_CUR
(当前位置),或 SEEK_END
(文件末尾)。
文件中已经预先存入abcdef
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读取文件
int ch = fgetc(pf);
printf("%c\n", ch);//a
//调整文件指针
fseek(pf, 2, SEEK_CUR);
ch = fgetc(pf);
printf("%c\n", ch);//d
ch = fgetc(pf);
printf("%c\n", ch);//e
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
3.2 ftell()
返回文件指针相对于起始位置的偏移量。
long ftell( FILE *stream );
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读取文件
int ch = fgetc(pf);
printf("%c\n", ch);//a
//调整文件指针
fseek(pf, -2, SEEK_END);
ch = fgetc(pf);
printf("%c\n", ch);//e
ch = fgetc(pf);
printf("%c\n", ch);//f
int ret = ftell(pf);
printf("%d\n", ret);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
3.3 rewind()
让文件指针的位置回到文件的起始位置。
void rewind( FILE *stream );
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读取文件
int ch = fgetc(pf);
printf("%c\n", ch);//a
//调整文件指针
fseek(pf, -2, SEEK_END);
ch = fgetc(pf);
printf("%c\n", ch);//e
ch = fgetc(pf);
printf("%c\n", ch);//f
int ret = ftell(pf);
printf("%d\n", ret);
//让文件指针回到起始位置
rewind(pf);
ch = fgetc(pf);
printf("%c\n", ch);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}