当前位置: 首页 > ops >正文

C语言文件流

输入输出 c语言

初步认识

  • 文件读写

  • 输入流和输出流 input stream output stream

  • buffer 缓冲区

  • 输入流的数据首先被暂存到一个叫做缓冲区的内存区域

再探scanf_s

 #include <stdio.h>​int main(void) {// 1.数的输入int age;printf("输入你的年龄:");scanf_s("%d", &age);    // 不需要加buffer 数没有缓冲区的概念 printf("年龄:%d\n", age);​// 2.字符串的输入char name[50];​printf("输入你的名字:");scanf_s("%49s", name, 50);  //scanf_s("%s", name, (unsigned int)sizeof(name));printf("Hello,%s\n", name);​// 3.字符的输入char ch;​printf("输入字符:");scanf_s("%c", &ch, 1);printf("字符:%c", ch);​return 0;}​

scanf_s返回值

 #include <stdio.h>​int main(void) {int number;int result;​puts("输入一个整数:");​result = scanf_s("%d", &number);​if (result == 1) {printf("你输入了有效的整型值:%d", number);}else if (result == EOF) {// End of file 通常为 -1// 专门用来指示文件读取或输入操作已经达到了数据源的末尾// 在终端中如果要把输入的东西撤销掉可以用ctrl+cprintf("An error occurred or end of file was reached");return 1;   // 表示程序出现错误的结束输出}else {printf("Invalid input for integer.\n");return 1;}​return 0;}​

流(stream)

  1. 文件流:磁盘 用于读取与写入在磁盘上的文件

  2. 标准I/O流:

    stdin:默认连接到键盘,用于程序输入

    stdout:默认连接到控制台或者是屏幕,用于程序输入

    stderr:默认连接到控制台或者是屏幕,专门输出错误信息和警告,使得其能够被区分开来或者是重定向到不同的目的地

  3. 管道流:用于进程之间的通信(IPC),允许一个进程输出成为另一个进程的输入

  4. 内存流:允许你将流与内存缓冲区关联,使得你可以向内存中读写数据,就像操作文件一样

  5. 网络流:套接字(Sockets)

  6. 设备流:特殊文件或者是设备 打印机

C语言用FILE* stream来操作

fopen_s,fgetc,fgets,fclose,读取r模式

 #include <stdio.h>#include <inttypes.h>​int main(void) {​FILE* file_stream = NULL;   //c语言操作流要使用的​char buffer[256];   //创建缓冲区​// fopen()打开文件的函数// fopen_s()跟缓冲区相关的函数,微软提供了_s的函数 传递的参数FILE** _Stream(使用的流),char const* _FileName(文件名), char const* _Mode(模式)​//打开文件设定文件路径要读取的文件,指定文件的操作模式rfopen_s(&file_stream, "C:\\c_learning\\c_stream.txt", "r");     // \\是转义序列输出\   "r" read读​​//fgets(buffer, sizeof(buffer), file_stream); 从文件中读取一行​while (fgets(buffer, sizeof(buffer), file_stream) != NULL) //停止循环可以用!= NULL {printf("%s", buffer);}​fclose(file_stream);​return 0;}

文件路径不对,文件不存在, 文件出现了异常,文件没有权限访问如何处理?

引入头文件#include <stdlib.h> #include <errno.h>

对14行进行修改

 errno_t err = fopen_s(&file_stream, "C:\\c_learning\\c_stream.txt", "r");       ​if (err != 0 || file_stream == NULL) {perror("Error opening file");return EXIT_FAILURE;}

当我们将文件路径更改后不会终止程序的输出 会输出Error opening file: No such file or directory

 #include <stdio.h>#include <inttypes.h>#include <stdlib.h>#include <errno.h>​int main(void) {​FILE* file_stream = NULL;   //c语言操作流要使用的​char buffer[256];   //创建缓冲区​// fopen()打开文件的函数// fopen_s()跟缓冲区相关的函数,微软提供了_s的函数 传递的参数FILE** _Stream(使用的流),char const* _FileName(文件名), char const* _Mode(模式)​//打开文件设定文件路径要读取的文件,指定文件的操作模式rerrno_t err = fopen_s(&file_stream, "C:\\c_learning\\c_stream.txt", "r");       // \\是转义序列输出\   "r" read读​​​if (err != 0 || file_stream == NULL) {perror("Error opening file");return EXIT_FAILURE;}​​while (fgets(buffer, sizeof(buffer), file_stream) != NULL) //停止循环可以用!= NULL {printf("%s", buffer);}​int ch;​// fgetc一个一个字符去获取 返回的是ASCII while ((ch = fgetc(file_stream)) != EOF)    //!= EOF也可以让它持续读取{putchar(ch);}​fclose(file_stream);​return 0;}

结果只会输出一次文本内容,因为file_stream指针把内容读完了,循环读完了,指针指向最后了,再往下什么都没有

如何解决只读一次的问题?

使用rewind()函数

在32行int ch;前面加上

 memset(buffer, 0, sizeof(buffer));​rewind(file_stream);

fclose()的优化 涉及文件写入就要按照下面的写法规范

 if (fclose(file_stream) != 0){perror("Error closing file!");return EXIT_FAILURE;}

fputs、fputc、w模式

 #include <stdio.h>#include <stdlib.h>​int main(void) {​FILE* file_ptr = NULL;​errno_t err = fopen_s(&file_ptr, "C:\\c_learning\\c_stream.txt", "w");  //"w"写入空的文件,若里面有内容,则先前的内容全部销毁​if (err != 0 || file_ptr == NULL) {perror("Failed to open file");return EXIT_FAILURE;}​// fputc() fputs() fprintf_s() 用与写入fputc('H', file_ptr);fputc('i', file_ptr);fputc('\n', file_ptr);​fputs("This is a line written by fputs.\n", file_ptr);​fprintf_s(file_ptr, "Numbers:%d, %f, %s\n", 10, 3.14, "End of example");    //格式化写入​fclose(file_ptr);​puts("File 'txt' has been written successfully");return 0;}

ftell、fseek、rewind、r+

txt内容为上一节输入的内容

#include <stdio.h>
#include <stdlib.h>int main(void) {FILE* file_ptr = NULL;errno_t err = fopen_s(&file_ptr, "C:\\c_learning\\c_stream.txt", "r+");	//r+打开以便读取和写入,文件必须存在if (err != 0 || file_ptr == NULL) {perror("Failed to open file");return EXIT_FAILURE;}long position = ftell(file_ptr);printf("当前位置:%ld\n", position);		//0char buffer[100];if ((fgets(buffer, sizeof(buffer), file_ptr)) != NULL) {printf("从文件读取:%s", buffer);		//Hi//再次使用ftell获取新位置position = ftell(file_ptr);printf("读取后的新位置:%ld\n", position);	//4 0:H 1:i 2:\r 3\n	windows中\r\n构成换行,fgets会把转义字符一起获取}//使用fseek函数移动到指定位置fseek(file_ptr, 0, SEEK_SET);printf("使用fseek后移动到文件的开始位置,SEEK_SET宏定义 = 0:%ld\n", ftell(file_ptr));	//0//rewind 重置文件指针到开头rewind(file_ptr);printf("使用rewind函数直接移动到开始位置%ld\n", ftell(file_ptr));	//0//关闭文件fclose(file_ptr);return 0;
}

fscanf_s

从流中读取格式化数据

//文件内容
//Hello 1234 5.67 Z#include <stdio.h>
#include <stdlib.h>FILE* stream;int main(void)
{long l;float fp;char s[81];char c;errno_t err = fopen_s(&stream, "C:\\c_learning\\c_stream.txt", "r");if (err)printf_s("The file fscanf.out was not opened\n");else{if (fscanf_s(stream, "%80s", s, (unsigned)_countof(s)) != 1) {  //%s:这是用于读取字符串的格式说明符。它会从输入流里读取连续的非空白字符,直至遇到空白字符(像空格、制表符、换行符等)才会停止。80指最多读取 80 个字符到目标字符串里printf("读取字符串失败!\n");}if (fscanf_s(stream, "%ld", &l) != 1) {printf("读取ld失败\n");}if (fscanf_s(stream, "%f", &fp) != 1) {printf("读取f失败\n");}if (fscanf_s(stream, " %c", &c, 1) != 1) {  //不加空格就会读取浮点数后面那个空格,输出一个空格printf("读取c失败\n");}// Output data read:printf("%s\n", s);printf("%ld\n", l);printf("%f\n", fp);printf("%c\n", c);fclose(stream);}
}

fprintf

fprintf:格式化向文件里写入东西

//文件内容
//ID:1
//Name:Frank
//Temperature : 36.5
//Grade : A#include <stdio.h>
#include <stdlib.h>FILE* stream;int main(void)
{long l;float fp;char s[81];char c;errno_t err = fopen_s(&stream, "C:\\c_learning\\c_stream.txt", "w+");if (err != 0) {printf_s("无法打开文件进行写入操作\n");return EXIT_FAILURE;}int id = 1;float temperature = 36.5f;char name[] = "Frank";char grade = 'A';fprintf(stream, "ID:%d\n", id);fprintf(stream, "Name:%s\n", name);fprintf(stream, "Temperature:%.1f\n", temperature);fprintf(stream, "Grade:%c\n", grade);fclose(stream);printf("数据写入完成\n");return 0;}

ferror,feof,clearerr

ferror:错误检查 检查文件流是否有错误发生 有错误返回非零值,无错误返回0

feof:错误检查 检查文件的指针是否到达了文件的末尾 到达返回非零值 没到达返回0

clearerr:清除错误 清除与文件流相关的错误标志

 #include <stdio.h>#include <stdlib.h>​FILE* file_ptr;​int main(void){errno_t err = fopen_s(&file_ptr, "C:\\c_learning\\c_stream.txt", "r");if (err != 0) {printf_s("无法打开文件进行写入操作\n");return EXIT_FAILURE;}​char buffer[100];​while (fgets(buffer, sizeof(buffer), file_ptr)) {printf("%s", buffer);}​if (ferror(file_ptr)) {perror("读取文件时候发生了错误");clearerr(file_ptr);}​if (feof(file_ptr)) {printf("已经到达文件的末尾\n");}else {printf("文件未达到末尾,可能因为发生了错误");}​​fclose(file_ptr);​return 0;}

抽离读写函数

 #include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>​void read_config_safe(const char* filename);​int main(void){const char* file_name = "C:\\c_learning\\game_config.txt";​read_config_safe(file_name);​return 0;}void read_config_safe(const char* filename) {FILE* file_ptr = NULL;errno_t err = fopen_s(&file_ptr, filename, "r");​if (err != 0 ||file_ptr == NULL) {char error_msg[256];strerror_s(error_msg, sizeof(error_msg), errno);​fprintf(stderr, "Failed to open config file for reading:%s\n", error_msg);exit(EXIT_FAILURE);}​char buffer[256];while (fgets(buffer, sizeof(buffer), file_ptr) != NULL) {printf("%s", buffer);}​fclose(file_ptr);​}​

文本内容:

# Game Configuration File

GraphicsQuality = High FullScreen = true Resolution = 1920 * 1080 AudioVolume = 80 EnableShadows = true; MaxNPCs = 50 Language = English

a模式追加

"a":在文件末尾打开以进行写入(追加),在新数据写入到文件之前不移除文件末尾(EOF)标记。如果文件不存在,则创建文件

 #include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>​void append_log_safe(const char* file_name, const char* message);int main(void){const char* log_name = "C:\\c_learning\\log.txt";​const char* str = "This is an appending text";​append_log_safe(log_name, str);​return 0;​//确保所有流关闭int numclosed = fcloseall();printf("Number of files closed by _fcloseall : % u\n", numclosed);}void append_log_safe(const char* file_name, const char* message) {FILE* file_ptr = NULL;errno_t err = fopen_s(&file_ptr, file_name, "a");​if (err != 0 || file_ptr == NULL) {char error_message[256];strerror_s(error_message, sizeof(error_message), errno);​fprintf(stderr, "Failed to open log file for appending:%s\n", error_message);exit(EXIT_FAILURE);​}printf("成功创建并追加!\n");​fprintf(file_ptr, "%s\n", message);​fclose(file_ptr);}​

w模式清空

结合上一节内容,使用w模式清空log的内容

 #include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>​void append_log_safe(const char* file_name, const char* message);void clear_log_file(const char* file_name);​int main(void){const char* log_file = "C:\\c_learning\\log.txt";​const char* str = "This is an appending text";​append_log_safe(log_file, str);​//使用w模式的函数清空文件clear_log_file(log_file);​return 0;​//确保所有流关闭int numclosed = fcloseall();printf("Number of files closed by _fcloseall : % u\n", numclosed);}void append_log_safe(const char* file_name, const char* message) {FILE* file_ptr = NULL;errno_t err = fopen_s(&file_ptr, file_name, "a");​if (err != 0 || file_ptr == NULL) {char error_message[256];strerror_s(error_message, sizeof(error_message), errno);​fprintf(stderr, "Failed to open log file for appending:%s\n", error_message);exit(EXIT_FAILURE);​}printf("成功创建并追加!\n");​fprintf(file_ptr, "%s\n", message);​fclose(file_ptr);}void clear_log_file(const char* file_name) {FILE* file_ptr = NULL;errno_t err = fopen_s(&file_ptr, file_name, "w");​if (err!= 0 || file_ptr == NULL) {char error_message[256];strerror_s(error_message,sizeof(error_message), errno);​fprintf(stderr, "Failed to open log file for clearing:%s\n", error_message);exit(EXIT_FAILURE);}printf("成功清除文件!\n");​//文件已经是w模式,不用多加其他内容,文件内容会直接清空fclose(file_ptr);​}​​

修改log r+

c语言中数据的更新用r+模式

r+:打开以便读取和写入,文件必须存在

 #include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>​#define BUFFER_SIZE 1000​void append_log_safe(const char* file_name, const char* message);errno_t update_log_record_s(const char* file_name, const char* search_str, const char* replace_str);int main(void){const char* log_file = "C:\\c_learning\\frank.log";​const char* search_str = "Memory usage exceeds 80% of available memory";​const char* replace_str = "[2023-02-14T12:36:00Z] [INFO] Memory usage is back to normal levels";​errno_t result = update_log_record_s(log_file, search_str, replace_str);​if (result != 0) {char error_msg[256];strerror_s(error_msg, sizeof(error_msg), result);fprintf(stderr,"An error occured:%s\n", error_msg);}else {printf("Record updated successfully");}​_fcloseall();return 0;​}void append_log_safe(const char* file_name, const char* message) {FILE* file_ptr = NULL;errno_t err = fopen_s(&file_ptr, file_name, "a");​if (err != 0 || file_ptr == NULL) {char error_message[256];strerror_s(error_message, sizeof(error_message), errno);​fprintf(stderr, "Failed to open log file for appending:%s\n", error_message);exit(EXIT_FAILURE);​}printf("成功创建并追加!\n");​fprintf(file_ptr, "%s\n", message);​fclose(file_ptr);}errno_t update_log_record_s(const char* file_name, const char* search_str, const char* replace_str) {//卫语句if (file_name == NULL || search_str == NULL || replace_str == NULL) {return EINVAL; //返回无效参数错误}​FILE* file_ptr = NULL;errno_t err = fopen_s(&file_ptr, file_name, "r+");if (err != 0 || file_ptr == NULL) {char error_msg[256];strerror_s(error_msg, sizeof(error_msg), errno);​fprintf(stderr,"Failed to open config file for reading:%s\n", error_msg);exit(EXIT_FAILURE);​}char buffer[BUFFER_SIZE];long position = 0;int found = 0;​while (fgets(buffer, BUFFER_SIZE, file_ptr) != NULL) {if (strstr(buffer, search_str)!= NULL) {found = 1;//ftell会保存当前位置 记录下来position = ftell(file_ptr) - (long)strlen(buffer) - 1; //减1以确保从行首开始替换break;   // 找到第一个匹配项之后,立刻停止}}​if (found) {fseek(file_ptr, position, SEEK_SET); //移动找到记录的位置​//计算替换文本和源文本的长度差异size_t replace_len = strlen(replace_str);size_t search_len = strlen(search_str);​if (replace_len > BUFFER_SIZE - 1 || search_len > BUFFER_SIZE - 1) {fclose(file_ptr);​return ERANGE;   //返回错误码,表示字符串长度超出范围}​//写入新记录,清除所在位置的行数据memset(buffer, ' ', strlen(buffer)- 1);  //用空格去填充,保持文件大小不变​buffer[strlen(buffer) - 1] = '\n';   //保留换行符​fseek(file_ptr, position, SEEK_SET); //重新回到标记行的开始​fputs(buffer, file_ptr); //彻底清除原来行的内容​fseek(file_ptr, position, SEEK_SET); //重新回到标记行的开始​int result = fputs(replace_str, file_ptr);   //写入替换的字符​if (result == EOF) {fclose(file_ptr);return errno;}}else {fclose(file_ptr);return ENOENT;   //返回未找到的匹配项}fclose(file_ptr);return 0;​}

fflush()函数(略过)

立刻将缓冲区的数据保存

多线程用

错误日志可以用

bin二进制文件的写入与读取 wb和rb模式

二进制写入:游戏设置保存

 #include <stdio.h>#include <stdlib.h>​typedef struct GameSettings {float volume;int resolution_x;int resolution_y;int difficulty;​} GameSettings;​void save_game_settings(const GameSettings* settings, const char* filename);​int main() {​// fread// fwrite// 读写二进制​// 创建实例GameSettings settings = {0.75, 1920, 1080, 2};save_game_settings(&settings, "C:\\c_learning\\game_settings.bin");return 0;}void save_game_settings(const GameSettings* settings, const char* filename) {FILE* file;errno_t err = fopen_s(&file, filename, "wb");   //wb 写入二进制if (err != 0 ||file == NULL) {perror("无法打开文件进行写入操作");return;}​fwrite(settings, sizeof(GameSettings), 1, file);fclose(file);​}​​​

二进制读取:游戏设置读取

 #include <stdio.h>#include <stdlib.h>​typedef struct GameSettings {float volume;int resolution_x;int resolution_y;int difficulty;​} GameSettings;​​void load_game_settings(GameSettings* settings, const char* filename);int main() {​// fread// fwrite// 读写二进制​GameSettings load_settings;​load_game_settings(&load_settings, "C:\\c_learning\\game_settings.bin");​printf("游戏设置已经加载\n");​printf("音量:%f\n分辨率:%dx%d\n难度:%d星\n", load_settings.volume,load_settings.resolution_x,load_settings.resolution_y,load_settings.difficulty);​​​​​​return 0;}​void load_game_settings(GameSettings* settings, const char* filename) {FILE* file;errno_t err= fopen_s(&file, filename, "rb");if (err!= 0||file==NULL) {perror("无法打开文件进行读取操作");return;}​fread(settings, sizeof(GameSettings), 1, file);​fclose(file);​}​

复制文件

 #include <stdio.h>#include <stdlib.h>​int main() {FILE* source_file, * target_file;​char source_path[] = "C:\\c_learning\\c_stream.txt";​char target_path[] = "C:\\c_learning\\copy_stream.txt";​char buffer[1024];​size_t byte_read;​errno_t err = fopen_s(&source_file, source_path, "rb");​if (err != 0 ||source_file == NULL) {perror("无法打开源文件");return EXIT_FAILURE;​}​err = fopen_s(&target_file, target_path, "wb");if (err!= 0 || target_file == NULL) {perror("无法打开目标文件");fclose(source_file);return EXIT_FAILURE;}​while ((byte_read = fread(buffer, 1, sizeof(buffer), source_file)) > 0) {fwrite(buffer, 1, byte_read, target_file);}​_fcloseall();​puts("文件复制完成");​​​​return 0;}
http://www.xdnf.cn/news/5183.html

相关文章:

  • 局域网常用的测速工具,Iperf3使用教程
  • QTableWidget实现多级表头、表头冻结效果
  • leetcode 349. Intersection of Two Arrays
  • 独立按键控制LED
  • [杂谈随感-13]: 人的睡眠,如何布置床的位置比较有安全?感?
  • HashMap中put()方法的执行流程
  • Python数据分析案例74——基于内容的深度学习推荐系统(电影推荐)
  • libwebsockets:高性能跨平台WebSocket库实践指南
  • C++——继承
  • 线程安全 1_线程安全
  • Ubuntu22.04怎么退出Emergency Mode(紧急模式)
  • Python环境搭建指南
  • 【redis 初阶】linux 上安装 redis
  • 电池的寿命(不清楚是什么类型/虽然有标明是贪心)
  • NVMe控制器IP设计之接口模块
  • 机器学习 day02
  • PD快充诱骗协议芯片XSP04D与主板共用一个Type-C和电脑传输数据
  • 关于Spring
  • 小刚说C语言刷题—1078求恰好使s=1+1/2+1/3+…+1/n的值大于X时n的值
  • 巡检机器人数据处理技术的创新与实践
  • 【Redis】string
  • Git 时光机:修改Commit信息
  • Java零组件实现配置热更新
  • gitkraken 使用教程
  • ai agent(智能体)开发 python3基础14:在python 中 总能看到方法里面套方法,那什么时候用这种方式合适呢?
  • Python常见面试题
  • LWIP的IP协议笔记
  • 通俗的理解MFC消息机制
  • 理解计算机系统_并发编程(2)_基于I/O复用的并发(一):select浅解
  • 如何理解编程中的递归、迭代与回归?