【文件操作:解锁高效读写与管理技巧】(上):https://developer.aliyun.com/article/1424823
那么再来写练一下文本行输出函数
int fputs ( const char * str, FILE * stream );
- 将由 str 指向的 C 字符串写入流中。
- 该函数从指定地址(str)开始复制,直到遇到终止空字符('\0')为止。终止空字符不会被复制到流中。
- 注意,fputs 与 puts 的区别不仅在于可以指定目标流,而且 fputs 不会写入额外的字符,而 puts 会自动在末尾追加换行字符。
#include<stdio.h> int main() { FILE* pf = fopen("data.txt","w"); if (!pf) { perror("fopen"); return 1; } //写文件 - 写一行 - 输出 //int fputs ( const char * str, FILE * stream ); fputs("hello world\n",pf); fputs("big dream\n", pf); //这两句话在文件中是一行还是两行? 两行 //关闭文件 fclose(pf); pf = NULL; return 0; }
输出结果:
文本输入函数:
int fgetc ( FILE * stream );
- 返回指定流的内部文件位置指示器当前指向的字符。然后,内部文件位置指示器会向下一个字符推进。
- 如果在调用时流已经到达文件末尾,该函数返回 EOF 并为该流设置文件末尾指示器 (feof)。
- 如果发生读取错误,该函数返回 EOF 并为该流设置错误指示器 (ferror)。
- fgetc 和 getc 是等价的,但在某些库中 getc 可能被实现为宏。
#include<stdio.h> int main() { FILE* pf = fopen("data.txt","r"); if (!pf) { perror("fopen"); return 1; } //读文件 - 读一行 - 输入 //char * fgets ( char * str, int num, FILE * stream ); char arr[10] = { 0 }; fgets(arr, 10, pf); printf("%s\n", arr); //关闭文件 fclose(pf); pf = NULL; return 0; }
运行结果:
上面的结果发现输出了两个换行,说明fgets在获取到num-1(留一个位置给'\n')个字符之后会自动换行。如果该字符没有读完,下次读取就会取消第一次读取的换行,将第二次的输出字符,直至这个字符串读完再换行。
格式输出函数:
int fprintf ( FILE * stream, const char * format, ... );
- 将由 format 指向的 C 字符串写入流中。如果 format 包含格式说明符(以 % 开头的子序列),则会格式化并插入 format 后面的附加参数,替换相应的格式说明符。
- 在 format 参数之后,该函数期望至少有与 format 指定的格式相同数量的附加参数。
#include<stdio.h> int main() { FILE* pf = fopen("data.txt","w"); if (!pf) { perror("fopen"); return 1; } //写文件 - 输出 //int fprintf ( FILE * stream, const char * format, ... ); fprintf(pf,"%d %lf",520,13.14); //关闭文件 fclose(pf); pf = NULL; return 0; }
结果:
格式输入函数
int fscanf ( FILE * stream, const char * format, ... );
- 从流中读取数据,并根据参数 format 将它们存储到附加参数所指向的位置。
- 附加参数应该指向已经分配的对象,其类型由 format 字符串中对应的格式说明符指定。
#include<stdio.h> int main() { int a; double d; FILE* pf = fopen("data.txt","r"); if (!pf) { perror("fopen"); return 1; } //读文件 - 输入 //int fscanf ( FILE * stream, const char * format, ... ); fscanf(pf, "%d %lf", &a, &d); //关闭文件 fclose(pf); pf = NULL; return 0; }
二进制输出:
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
- 将由 ptr 指向的内存块中的 count 个元素写入流的当前位置。
- 流的位置指示器会根据写入的总字节数向前推进。
- 在内部,该函数将 ptr 指向的块解释为类型为 unsigned char 的 (size*count) 个元素的数组,并按顺序将它们写入流中,就像对每个字节调用了 fputc 一样。
#include<stdio.h> struct S { int a; double d; }; int main() { struct S s = { 520,13.14 }; FILE* pf = fopen("data.txt", "wb");//二进制打开文件 if (!pf) { perror("fopen"); return 1; } //写文件 - 输出 //size_t fwrite(const void* ptr, size_t size, size_t count, FILE * stream); fwrite(&s, sizeof(struct S), 1, pf); //关闭文件 fclose(pf); pf = NULL; return 0; }
输出:二级制文件
二进制输入:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
- 从流中读取 count 个元素,每个元素大小为 size 字节,并将它们存储在由 ptr 指定的内存块中。
- 流的位置指示器会根据成功读取的总字节数向前推进。
- 如果成功读取,总共读取的字节数为 (size*count)。
#include<stdio.h> struct S { int a; double d; }; int main() { struct S s = { 0 }; FILE* pf = fopen("data.txt", "rb");//二进制读出文件 if (!pf) { perror("fopen"); return 1; } //读文件 - 输入 //size_t fread ( void * ptr, size_t size, size_t count, FILE * stream ); fread(&s, sizeof(struct S), 1, pf); printf("%d %lf", s.a, s.d); //关闭文件 fclose(pf); pf = NULL; return 0; }
运行结果:
4.2 对比一组函数:
int sscanf ( const char * s, const char * format, ...);
- 从字符串 s 中读取数据,并根据参数 format 将其存储到附加参数所指向的位置,就像使用 scanf 一样,但是从字符串 s 而不是标准输入(stdin)读取。
- 附加参数应该指向已经分配的对象,其类型由 format 字符串中对应的格式说明符指定。
int sprintf ( char * str, const char * format, ... );
- 该函数将以与使用 printf 时相同的文本组成一个字符串,但不会将其打印,而是将内容存储为 C 字符串,存放在由 str 指向的缓冲区中。
- 缓冲区的大小应足够大,以容纳整个结果字符串(请参阅更安全的版本 snprintf)。
- 内容后会自动追加一个终止空字符。
- 在 format 参数之后,该函数期望至少有足够的附加参数以满足 format 的需求。
#include<stdio.h> struct S { int a; double d; char arr[10]; }; int main() { struct S s = { 12,3.14,"hello" }; char str[100]; struct S temp = { 0 }; //int sprintf ( char * str, const char * format, ... ); sprintf(str, "%d %lf %s", s.a, s.d, s.arr); printf(str); //int sscanf ( const char * s, const char * format, ...); sscanf(str, "%d %lf %s", &(temp.a), &(temp.d), &(temp.arr)); printf("%d %lf %s\n", temp.a, temp.d, temp.arr); return 0; }
- scanf, fscanf, sscanf:
scanf: 从标准输入(键盘)读取数据,并根据指定的格式进行解析,将数据存储到给定的变量中。
fscanf: 从指定的文件流中读取数据,并根据指定的格式进行解析,将数据存储到给定的变量中。
sscanf: 从指定的字符串中读取数据,并根据指定的格式进行解析,将数据存储到给定的变量中。
- printf, fprintf, sprintf:
printf: 将格式化的数据输出到标准输出(屏幕)。
fprintf: 将格式化的数据输出到指定的文件流。
sprintf: 将格式化的数据输出到指定的字符串缓冲区。
总结区别:
scanf, fscanf, sscanf 主要用于输入操作,从不同来源(标准输入、文件、字符串)读取数据。
printf, fprintf, sprintf 主要用于输出操作,将格式化的数据输出到不同的目标(标准输出、文件、字符串缓冲区)中。
5. 文件的随机读写
5.1 fseek - 根据文件指针的位置和偏移量来定位文件指针。
int fseek ( FILE * stream, long int offset, int origin );
stream:指向标识流的 FILE 对象的指针。
offset:
- 二进制文件:从 origin 确定的位置偏移的字节数。
- 文本文件:要么为零,要么为 ftell函数 返回的值。
origin:用作偏移参考的位置。
- SEEK_SET 文件开头
- SEEK_CUR 文件指针的当前位置
- SEEK_END 文件末尾
#include <stdio.h> int main() { FILE* pFile; pFile = fopen("example.txt", "wb"); fputs("This is an apple.", pFile);///写文件 - 输出 fseek(pFile, 9, SEEK_SET);//从起始位置开始偏移 //fseek(pFile, -8, SEEK_END);//从起始位置开始偏移 //偏移量为9的字符串换为 sam fputs(" sam", pFile);///写文件 - 输出 fclose(pFile); pFile = NULL; return 0; }
运行结果:
【文件操作:解锁高效读写与管理技巧】(下):https://developer.aliyun.com/article/1424833