添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
有爱心的松鼠  ·  postgres 数据库 sql ...·  1 年前    · 
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

缓冲区一般是行设计....   也就是缓冲区大小一般就叫做一行, 一般就是1024字节 char buff[1024]

有了缓冲区, 我们就可以按照缓冲区大小进行读写操作, 基于行, 缓冲区 进一步向上封装成了C语言的  scanf 和 printf 这样的 可以跨平台使用的函数

缓冲区好处 :

可以屏蔽掉低级I/O的实现  (  低级IO就是基于操作系统内核实现的系统调用), 可以减少系统调用次数 (用户空间向内核空间切换次数) 提高效率   方便写出可移植的程序。

有了行的概念, 可以实现行读取, 解析整个缓冲区中的内容返回一个行

二. C标准IO + C++标准IO  刨析及其解决 字符串输入 空格结束问题刨析   (以及常用IO函数刨析) if ((fp = fopen("./test.txt", "r+")) == NULL) { perror("Error open file"); exit(EXIT_FAILURE); char ch; //一定先读取之后才判断是否是结尾 或者这样写 ch = fgetc(); while (ch != EOF) { ch = fgetc(fp); //又或者是这样写 ch = fgetc(fp); while (!feof(fp)) { fputc(ch, stdout);//操作 ch = fgetc(fp); while ((ch = fgetc(fp)) != EOF) { fputc(ch, stdout); //操作 fclose(fp); //最后一定关闭文件, 养成好习惯 return 0; if ((fp = fopen("./test.txt", "r+")) == NULL) { perror("Error open file"); exit(EXIT_FAILURE); int a, b; for (int i = 0; i < 3; ++i) { fprintf(fp, "%d\t%d\n", a = rand() % 1024, b = rand() % 1024); printf("a: %d, b: %d\n", a, b); /* //先写入后读取 int aa, bb; for (int i = 0; i < 3; ++i) { fscanf(fp, "%d\t%d\n", &aa, &bb); printf("aa: %d, bb: %d\n", aa, bb); fclose(fp); return 0; int main() { //针对结构体数组其实用二进制块读写操作简直不要太爽 (小缺陷: 乱码) STU s[3] = { { 18, "张三" }, { 20, "李四" }, { 24, "王五" } }; FILE* fp; if ((fp = fopen("myfile.bin", "rb+")) == NULL) { perror("Error open file"); exit(EXIT_FAILURE); //fwrite(s, sizeof(STU), 3, fp); //先写入之后屏蔽写入放开读取测试 int n = fread(s, sizeof(STU), 3, fp);//从里面读取 //n : 成功读取的小块数目 for (int i = 0; i < n; ++i) { printf("name: %s, age: %d\n", s[i].name, s[i].age); fclose(fp); return 0; if ((fp = fopen("test.txt", "r+")) == NULL) { perror("Error open file"); exit(EXIT_FAILURE); //首先是演示常用功能1:fseek + ftell 可获取文件大小 fseek(fp, 0, SEEK_END);//定位文件末尾 int file_size = ftell(fp);//获取文件开头到当前位置字节数 printf("file_size: %d\n", file_size); //演示功能 2: fseek 如何达到和rewind一致效果 //rewind(fp); fseek(fp, 0, SEEK_SET); printf("cur position is %d\n", ftell(fp)); return 0;

其实上述两个步骤可以合二为一(合成调用有参构造,在构造函数中传入文件参数)

调用成员函数进行文件读写操作  或者是  使用C++专属的  流式  操作, 其实就是对于 operator << 和  operator >> 运算符的重载, 利用 << 和  >> 运算符 进行直观的文件读写操作

( 其实底层的 << 和 >>  本质 还是在重载函数中   进行的调用成员函数处理方式,只不过不需要我们写了. 直接用<< 和 >> 非常便捷)

文本读写操作

  • 第一个文本读get方法:
  • 二进制文件读写操作 + << >> 文件读写操作:   (     使用  << 和 >> 替代了  C 中的格式化文件读写操作    )      <<  和   >> 插入提取运算符 重载 代替了  C 语言中的格式化输入输出方式

    首先 文件打开方式需要重新设置, 需要加入  ios::binary 进去,  然后是介绍两个函数, 几乎和C用法差不多, 只不过变成了类的方法,  read() 和 write() 方法   (缺陷, 还是乱码)

    ofstream ofs("test.txt", ios::out | ios::binary); ofs.write("Hello write\n", strlen("Hello write\n")); ofs.close(); ifstream ifs("test.txt", ios::in | ios::binary); if (!ifs) { cerr << "Error open file" << endl; exit(EXIT_FAILURE); //第一步先获取文件大小, 开缓冲区..... ifs.seekg(0, ifs.end); int length = ifs.tellg(); ifs.seekg(0, ifs.beg); char *buff = new char[length]; ifs.read(buff, length); //此处体现的C++ 判断读取的方式是直接 判断 ifs(对于bool的重载) //C语言则是通过返回值判断 if (ifs) { cout << "Read all bytes success and read " << length << " bytes" << endl; buff[length] = 0; cout << buff << endl; else { cerr << "Read error" << endl; exit(EXIT_FAILURE); ifs.close(); //有始有终, 虽然最后ifstream的析构中会处理 return 0; ofstream ofs("test.txt"); ofs << age << "\t" << name; //直接进行数据流入 ofs.close(); //好习惯 //(类比 cout << 向标准输出设备文件显示器上输出) ifstream ifs("test.txt"); if (!ifs) { cerr << "Error open file" << endl; exit(EXIT_FAILURE); ifs >> age >> name; //数据流出操作 //(类比 cin >> 从标准输入设备文件键盘上读取数据存储到内存) cout << "age: " << age << ", name: " << name << endl; ifs.close(); //好习惯 return 0; ofs.write(info._ip, strlen(info._ip)); ofs.put('\n'); string portstr = to_string(info._port); ofs.write(portstr.c_str(), portstr.size());*/ // C++流多提供的,其他的c一样都可以实现 ofstream ofs(_filename); ofs << info._ip <<"\n"<< info._port; void ReadTxt(ServerInfo& info) //ifstream ifs(_filename); //ifs.getline(info._ip, 20); //char portbuff[20]; //ifs.getline(portbuff, 20); //info._port = stoi(portbuff); // C++流多提供的,其他的c一样都可以实现 ifstream ifs(_filename); ifs >> info._ip >> info._port; private: string _filename; //int main() // ServerInfo rinfo; // ServerInfo winfo = {"192.0.0.1", 8000}; // // 读写 -- 二进制 -- 读写简单、高效快捷。 缺点:除了字符和字符串,内存中写到文件,是乱码 // /*ConfigManager cfbin("config.bin"); // cfbin.WriteBin(winfo);*/ // //ConfigManager cfbin("config.bin"); // //cfbin.ReadBin(rinfo); // // 读写 -- 文本 // //ConfigManager cftxt("config.txt"); // //cftxt.WriteTxt(winfo); // ConfigManager cftxt("config.txt"); // cftxt.ReadTxt(rinfo); // return 0; strcpy(name, "12345"); //先改一下 这样后面才知道是不是流出了数据的 ss >> age >> name; cout << "age: " << age << " " << "name: " << name << endl; return 0; string serialize(TreeNode* root) { string ans = ""; if (root == NULL) return ans; //直接返回就是了 stringstream in_out; in_out << root->val; //流入根部 in_out >> ans; //每次将ss流入到ans中 1.后面只要右孩子 就需要加上 () 2.如果有右孩子加上 , 3. 先 ( + 左孩子序列 + , + 右孩子序列 + ) if (root->left || root->right) { ans += "("; //只要有一个孩子加上( ans += serialize(root->left); // + 左孩子 if (root->right) ans += ","; //存在右孩子 + , ans += serialize(root->right); if (root->left || root->right) { ans +=")"; return ans; int toi(const string& s, int& i) { int val = 0; bool flag = 0; //标记负数 if (s[i] == '-') { flag = 1; i += 1; //跳过负号 for (; s[i] >= '0' && s[i] <= '9'; ++i) { val = val * 10 + (s[i] - '0'); if (flag) val *= -1; return val; // Decodes your encoded data to tree. TreeNode* deserialize(string data) { //广义表转二叉树 TreeNode* root = NULL, *pTemp = NULL; //保存 根部 + 临时节点 stack<TreeNode*> st; bool flag = 0; //标记是否存在右孩子 for (int i = 0; i < data.size(); ++i) { switch(data[i]) { case '(' : { st.push(pTemp);// ( : 节点入栈 flag = 0; // 重置 flag } break; case ',' : { flag = 1;//说明存在右孩子 } break; case ')' : { root = st.top();//记录可能的根部 st.pop(); //) pop节点 } break; default : { //说明是一个实际节点 int val = toi(data, i); //提取数据 pTemp = new TreeNode(val); if (!st.empty() && flag == 0) { st.top()->left = pTemp; //栈顶节点的左孩子 } else if (!st.empty() && flag == 1) { st.top()->right = pTemp;//栈顶节点的右孩子 i -= 1; //(需要体会) i -= 1(因为在 toi中 i走到哪里去了?) } break; if (root == NULL && pTemp) root = pTemp; //仅有一个孩子 return root;

    解决上述题目 首先需要运用序列化 利用 stringstream 将 所有的 int数据转换为 string 并且实现字符串的广义表形式表示

    解码 就是广义表转二叉树的过程, 如下博客可以解决这个问题:https://blog.csdn.net/weixin_53695360/article/details/122895869

    六. 总结本章

    首先我们从为何需要缓冲区 入手解析 C  和  C++ 这些对系统调用进一步封装实现的  更高层的IO方法的好处  (减少系统调用次数)  提高效率      便利写出可移植性更好的代码

    然后解析 C 语言 IO  和 C++  IO 的 基本 函数 和 C++流式IO的引入, C++流式IO  核心关键在于operator << 和 operator >> 运算符的重载实现.  以及 C 语言 利用  %[^\n]%*c 实现输入字符串仅仅以回车结束,  getline(cin, s); 实现 C++的字符串输入仅回车结束

    C语言常见的文件IO    文本  + 二进制   +   格式化  + 定位

    C++ 常见的文件IO      文本   +   二进制    + 流式(代替格式化) + 定位

    sscanf + sprintf 的字符串序列化 +  反序列化 实现    +  整形转字符串   +   字符串拼接   转换为    C++中的   利用 stringstream实现的  序列化和反序列化