目录
1. 什么是文件
2. 为什么要有文件
3. 文件名
4. 文件类型
5. 文件指针
6. 文件的打开和关闭
// 函数原型
// filename: 文件名
// mode: 打开文件的方式
// return val: 返回一个文件指针,这个指针指向这个被打开的文件
FILE *fopen( const char *filename, const char *mode );
// 函数原型
// 关闭一个被打开的文件
// stream: 对应的文件指针
// return val: 如果成功关闭,返回0;失败返回EOF
int fclose( FILE *stream );
void Test1(void)
{
// 以文本写的方式打开文件
FILE* fp = fopen("log.txt", "w");
// 打开失败返回NULL
if (fp == NULL)
{
perror("open failed");
exit(-1);
}
else
{
// 关闭文件
fclose(fp);
}
}
7. 文件的顺序读写
7.1. fgetc
// Read a character from a stream or stdin;
// 读取失败会返回EOF(end of file)
// success: 返回读取的字符
int fgetc( FILE *stream );
void Test2(void)
{
// 以文本读打开一个文件
FILE* fp = fopen("Test.c", "r");
assert(fp);
// 如果没有遇到EOF,就继续读
while (!feof(fp))
{
//每次读取一个字符,并向标准输出写入
printf("%c", fgetc(fp));
}
// 关闭一个文件
fclose(fp);
}
7.2. fputc
Writes a character to a stream or to stdout.
// ch: 你要写入的字符
// stream: 你要向哪个流写入
// success: return ch
// failed: return EOF
int fputc( int c, FILE *stream );
void Test3(void)
{
char ch = 'a';
while (ch <= 'z')
{
// 向标准输出(stdout)写入ch
fputc(ch, stdout);
++ch;
}
}
7.3. fgets
//Get a string from a stream.
// string: 数据的存储位置
// n: 每次最大读取字符的个数
// stream: 从那个流中读?
// success: 返回读取字符串的起始位置
// failed: 返回NULL
char *fgets( char *string, int n, FILE *stream );
#define BUFFER_MAX 64
void Test4(void)
{
char str[BUFFER_MAX] = { 0 };
FILE* fp = fopen("Test.c", "r");
assert(fp);
while (fgets(str, BUFFER_MAX, fp) != NULL)
{
printf("%s", str);
}
fclose(fp);
}
7.4. fputs
// Write a string to a stream.
// string 你要写入的字符串的起始地址
// stream 你要想哪个流写入
// success: 返回一个!负值
// failed: 返回EOF
int fputs( const char *string, FILE *stream );
void Test5(void)
{
const char* str = "hehe\n";
for (size_t i = 0; i < 5; ++i)
{
// 向标准输出写入特定字符串
fputs(str, stdout);
}
}
7.5. fscanf
//Read formatted data from a stream.
// 从特定流(所有输入流)读取格式化数据,与scanf十分类似
// 只不过scanf是固定的从标准输入流读取数据
int fscanf( FILE *stream, const char *format [, argument ]... );
#define BUFFER_MAX 64
void Test6(void)
{
FILE* fp = fopen("log.txt1", "r");
assert(fp);
char str[BUFFER_MAX] = { 0 };
while (!feof(fp))
{
fscanf(fp, "%s", str);
printf("%s\n", str);
}
fclose(fp);
}
7.6. fprintf
// Print formatted data to a stream.
// 向特定流(所有输出流)写入格式化数据
// 与printf十分类似,不过printf是默认向标准输出流写入格式化数据
// success: 返回已写入的字节数
// failed: 返回一个负值
int fprintf( FILE *stream, const char *format [, argument ]...);
void Test7(void)
{
const char* str = "haha\n";
int* ptr = (int*)malloc(sizeof(int)* 5);
for (size_t i = 0; i < 5; ++i)
{
// 其返回值代表每次写入的字节数
// 向标准输出流写入特定字符串
ptr[i] = fprintf(stdout, "%s", str);
}
for (int i = 0; i < 5; ++i)
{
printf("%d ", *(ptr + i));
}
free(ptr);
ptr = NULL;
}
7.8. sscanf
// Read formatted data from a string
// buffer: 存储数据的起始地址
// sscanf 从一个字符串提取出格式化的数据
// failed: return EOF
int sscanf( const char *buffer, const char *format [, argument ] ... );
typedef struct PeoInfo
{
char name[15];
int age;
}Info;
void Test8(void)
{
const char* buffer = "cuihua 18";
Info tmp = { 0 };
// 从buffer这个字符串提取成格式化的数据
sscanf(buffer, "%s%d", tmp.name, &tmp.age);
printf("%s %d\n", tmp.name,tmp.age);
}
7.9. sprintf
// Write formatted data to a string.
// buffer: 存储将格式化的数据转为stirng的结果
// sprintf 就是将格式化的数据转化为一个字符串
int sprintf( char *buffer, const char *format [, argument] ... );
void Test9(void)
{
char buffer[BUFFER_MAX] = { 0 };
Info tmp = { "cuihua", 18 };
// 将格式化数据转化为一个字符串
sprintf(buffer, "%s %d\n", tmp.name, tmp.age);
printf("%s", buffer);
}
7.9. fread
// Reads data from a stream.
// buffer: 缓冲区
// size: 每次读取的字节数
// count: 要读取多少次
// stream: 从特定流读取
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
void Test10(void)
{
char str[BUFFER_MAX] = { 0 };
FILE* fp = fopen("Test.c", "r");
assert(fp);
// 从fp这个流中读取BUFFER_MAX-1个有效字符
fread(str, BUFFER_MAX - 1, 1, fp);
printf("%s", str);
fclose(fp);
}
7.10. fwrite
//Writes data to a stream.
// buffer: 指向被写入的数据
// size: 每次写多少个字节
// count: 写多少次
// stream: 向哪个流写入
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
void Test11(void)
{
const char* str = "hehe\n";
for (size_t i = 0; i < 5; ++i)
{
// 向标准输出流写入str这个指针指向的内容,每次写size个字节
fwrite(str, strlen(str), 1, stdout);
}
}
8. 文件的随机读写
8.1. fseek
//Moves the file pointer to a specified location.
// fseek 可以根据指针的位置 和 偏移量(offset) 来定位文件指针
// origin 初始位置
// SEEK_CUR 文件指针当前的位置
// SEEK_END 文件末尾的位置
// SEEK_SET 文件开始的位置
int fseek( FILE *stream, long offset, int origin );
void Test12(void)
{
const char* str = "abcdefg";
FILE* fp = fopen("data.txt", "w");
assert(fp);
fwrite(str, strlen(str), 1, fp);
// 此时data.txt的内容就是 abcdef
fclose(fp);
FILE* fp1 = fopen("data.txt", "r");
char ch = 0;
// 如果我按照顺序读取,那么第一次读必然是a
ch = fgetc(fp1);
printf("%c\n", ch); // 必定是a
// 那如果我此时像读取d呢
// 由于此时的文件指针fp指向了b,那么 + 2就到了d
// 故 offset = 2
fseek(fp1, 2, SEEK_CUR);
ch = fgetc(fp1);
printf("%c\n", ch); // d
// 那如果我此时像读取最后一个字符呢,也就是g,如何读取呢?
// SEEK_END 文件的末尾
fseek(fp1, -1, SEEK_END);
ch = fgetc(fp1);
printf("%c\n", ch); // g
fclose(fp1);
}
8.2. ftell
// Gets the current position of a file pointer.
// ftell函数可以返回当前文件指针相对于起始位置的偏移量
long ftell( FILE *stream );
void Test13(void)
{
FILE* fp = fopen("data.txt", "r");
// 这个文件的数据: abcdefg
assert(fp);
fseek(fp, -1, SEEK_END); // 此时这个文件指针指向g
printf("%d\n", ftell(fp)); // 此时就是6
fclose(fp);
}
8.3. rewind
//Repositions the file pointer to the beginning of a file.
// 让当前文件指针回到文件的起始位置
void rewind( FILE *stream );
void Test14(void)
{
FILE* fp = fopen("data.txt", "r");
// 这个文件的数据: abcdefg
assert(fp);
fseek(fp, -1, SEEK_END); // 此时这个文件指针指向g
printf("%d\n", ftell(fp)); // 此时就是6
rewind(fp); // 让这个文件指针回到文件的起始位置
printf("%d\n", ftell(fp)); // 此时就是0
fclose(fp);
}
9. 文件结束的判定
// Tests for end-of-file on a stream.
// 测试文件是如何结束的
// 如果遇到了EOF(即文件指针到了文件末尾),return !0
// otherwise, return 0
int feof( FILE *stream );