目录

一. IO缓冲区存在的意义    (屏蔽低级IO)​

二. C标准IO + C++标准IO  刨析及其解决字符串输入空格结束问题刨析   (以及常用IO函数刨析)​

三. C 文件IO (从常用函数刨析到具体案例实现)

四. C++ 文件IO (从常见方法刨析到 案例实现)

五. 从C语言的 fprintf 进化到 sstream  实现序列化和反序列化

六. 总结本章


一. IO缓冲区存在的意义    (屏蔽低级IO)

  • 缓冲区一般是行设计....   也就是缓冲区大小一般就叫做一行, 一般就是1024字节 char buff[1024]
  • 有了缓冲区, 我们就可以按照缓冲区大小进行读写操作, 基于行, 缓冲区 进一步向上封装成了C语言的  scanf 和 printf 这样的 可以跨平台使用的函数

缓冲区好处 :

  • 可以屏蔽掉低级I/O的实现  (  低级IO就是基于操作系统内核实现的系统调用), 可以减少系统调用次数 (用户空间向内核空间切换次数) 提高效率   方便写出可移植的程序。
  • 有了行的概念, 可以实现行读取, 解析整个缓冲区中的内容返回一个行

二. C标准IO + C++标准IO  刨析及其解决字符串输入空格结束问题刨析   (以及常用IO函数刨析)

  • FILE 的本质就是一个句柄  :   句柄思想, 使用简单的一个FILE* 就可以操作背后对应的文件, 做个比喻就是有点像是使用 遥控器 控制一个机器人, 通过对一个把手开关的简单操作, 将对应操作落实到一个比较复杂的东西上去,   操作 FILE就是操作文件 。。。 底层落实到 内核上的files_struct结构体上面去了
  •  fflush :    将缓冲区中的内容实时刷新写入到文件中去.     (文件不一定是 stdout 其他也可)
  • 其实可以简单做一个小小的测试....    如下使用sleep + printf()  +  fflush(stdout)  测试 fflush功能      stdin  + stdout    + stderr 是在一开始就打开的三个文件流...  操作系统给我们打开的            在  Linux 环境下测试才可获取结果:   windows环境下好像不行应该是做了优化
    [tangyujie@VM - 4 - 9 - centos ~]$ cat test.c
    #include <stdio.h>
    int main() {printf("haha");//fflush(stdout);while (1);return 0;
    }
  • 希望读者自行测试,  上述存在 fflush 和 屏蔽fflush 效果是完全不一样的, 屏蔽掉发现显示器上没有输出, 说明  缓冲区中的数据没有刷新到显示器上 (没有写入标准输出设备文件中去)  解除屏蔽则可以瞬间刷新
  • 然后接下来针对scanf提出一个小小要求 : 很多时候初学C语言的时候都在烦恼的问题. 想要输入一个完成的以行结束的字符串, 可以经常遇到  空格  就被截断的尴尬情况????? 咋办

此处给出格式化输入的办法:    专门应对 C语言想要输入字符串 但是不想被中间空格截断情况

#include <stdio.h>
int main() {char buff[256] = { 0 };scanf("%[^\n]%*c", buff);printf("buff: %s\n", buff);return 0;
}

 

  • C++ 中 为了充分体现面向对象编程的思想, 其中的  输入输出都是定义的类 然后重载 operator <<运算符 和  operator >> 运算符来实现的.  
  • 而且将  ios 类叫做流类的基类:          为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能.....
  • C++ 将其形象的比作数据流, 使得  C++中对于数据的输入输出操作更加直观  。。。。
  • C++标准库提供了4个全局流对象cin、cout、cerr、clog,使用cout进行标准输出,即数据从内存流向控制台(显示器)。使用cin进行标准输入即数据通过键盘输入到程序中,同时C++标准库还提供了cerr用来进行标 准错误的输出,以及clog进行日志的输出,从上图可以看出,cout、cerr、clog是ostream类的三个不同的 对象,因此这三个对象现在基本没有区别,只是应用场景不同。 在使用时候必须要包含文件并引入std标准命名空间。

注意点  :

  • 空格和回车都可以作为数据之间的分格符   :  如何解决空格不能输入问题????
  • cin和cout可以直接输入和输出内置类型数据, 但是自定义类型必须自己重载operator << 和 operator >>才可以为什么???

  使用  getline 全局函数 解决 cin  空格结束问题

int main() {string s;//cin >> s;               //空格就结束了, 达不到输入一行的效果getline(cin, s);        //成功读取一行,以回车键结束cout << s << endl;return 0;
}

内置类型, 标准内库已经帮助我们做好了重载了, 所以自定义类型可以直接进行输入

最后再解决一个C++ 中循环输入的疑惑问题, 为何C++可以支持 while (cin >> 对象 ) {操作;}    这样的奇葩操作???   cin  的返回值 就是 istream流对象

  • 这个操作的意思是什么???  意思就是说 返回值 istream 对象可以做判断, 对象如何做判断???
  • 其实是因为 C++在  ios 类中重载了  operator bool

三. C 文件IO (从常用函数刨析到具体案例实现)

  • 先是文本文件读写操作函数分析, 以及实际案例实操

  • 上述注意点,   以及所有文件读取操作的时候一定注意的就是 是不是文件末尾我们只有读取之后才知道, 所以一般为了避免对于文件末尾的多余操作, 很多时候会先读取后操作, 还有很多是在循环外面先读取一次文件, 其实都是这个道理

代码写起来, 学以致用

int main() {FILE* fp;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;
}

继续文本文件操作:    接下来介绍格式化输入输出函数....

测试使用:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main() {srand((unsigned int)time(NULL));FILE* fp;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;
}
  • 然后进行二进制读写操作, 同时这个也叫块读写操作, 每一次都是读取连续的内存块....
  • 二进制读写操作缺陷 :  会产生乱码 (对于非字符串会乱码)
  • 先函数图解刨析:   

学以致用, 常规用法:   一般来说二进制内存块文件读写操作都是针对数组 这种连续内存比较合适, 不论什么数组, 或者是结构体也是可以的......      核心关键 : 内存连续  多个内存小块(一个内存大块)      

typedef struct student {int age;char name[20];
}STU;
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;
}
  • 定位函数 常用图解刨析    (定的什么位, 文件指针所指位)

  • 活学活用, 上述 其实 rewind 完全是鸡肋了, 因为  fseek 完全可以代替其功能, 位异设置为0 直接起点文件指针设置为  SEEK_SET  可以达到一致效果:    如下代码端可以验证:

    int main() {FILE* fp;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++ 文件IO (从常见方法刨析到 案例实现)

基本面向对象式的实现文件读写操作,  核心 C++  相对于C   函数式 -----> 过度到 面向对象实现文件IO操作..     (fstream 基类 : 既可以完成文件读也可以完成文件写操作, ifstream 仅文件读操作, ofstream, 仅文件写操作,  C++文件读写操作 都是基于上面三个类的实例化对象完成的......)

图解刨析一下上述类的构造函数:

 C++文件操作流程

  • 定义一个  fstream\ifstream\ofstream 对象,调用默认构造函数
  • 调用open 成员函数 (打开文件, 建立 对象和磁盘文件的关联)
  • 其实上述两个步骤可以合二为一(合成调用有参构造,在构造函数中传入文件参数)
  • 调用成员函数进行文件读写操作  或者是  使用C++专属的  流式  操作, 其实就是对于 operator << 和  operator >> 运算符的重载, 利用 << 和  >> 运算符 进行直观的文件读写操作
  • ( 其实底层的 << 和 >>  本质 还是在重载函数中   进行的调用成员函数处理方式,只不过不需要我们写了. 直接用<< 和 >> 非常便捷)

文本读写操作

  • 第一个文本读get方法:

代码测试:

int main() {{ifstream ifs("test.txt"); //mode默认 ios::inif (!ifs) {cerr << "destruct ifs error" << endl;exit(EXIT_FAILURE);}char ch;/*方式1:while ((ch = ifs.get()) != EOF) {cout << ch;}*//*方式2:while (ifs.get(ch)) {cout << ch;}*///方式3:while (ifs) {cout << (char)ifs.get();}}ifs.close();       //也可以不写, 析构中会清理return 0;
}
  • 文本写put方法....

实例测试:

int main() {//文件写  默认是 ios::out, 不存在会create a fileofstream ofs("writefile.txt");char ch;//提示一个 \n回车换行键 作为结束cout << "Type some text (type a \\n to finish):" << endl; do {ch = cin.get();ofs.put(ch);} while (ch != '\n');return 0;
}

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

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

//基础案例:
int main() {//先写点东西进去, 然后才能够读取/*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;
}

流式用法, 替换C语言的格式化, 简易测试一下:

int main() { int age = 10;char name[20] = "张三";//先向文件中流入数据/*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;
}

来一个总的类 测试案例 (这个是比较常用的, ip + port管理类):

  • 两个(常用)函数刨析:string <-----> int   (C++的)

 char* <-----> int  C语言版本函数刨析   :

struct ServerInfo
{char _ip[20];int  _port;
};struct ConfigManager
{
public:ConfigManager(const char* filename):_filename(filename){}void ReadBin(ServerInfo& info){ifstream ifs(_filename);ifs.read(char*)&info, sizeof(info));}void WriteBin(const ServerInfo& info){ofstream ofs(_filename);ofs.write((char*)&info, sizeof(info));}void WriteTxt(const ServerInfo& info){/*ofstream ofs(_filename);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;
//}

文件定位操作

  • 函数刨析:   

测试代码:

int main() {ifstream ifs("test.txt");if (!ifs) {cerr << "Destruct ifstream obj error" << endl;exit(EXIT_FAILURE);}int length; ifs.seekg(0, ifs.end);length = ifs.tellg();ifs.seekg(0, ifs.beg);         //回到开头了cout << "file_size: " << length << endl;ifs.close();while (1);return 0;
}
int main() {ifstream ifs("test.txt");if (!ifs) {cerr << "Destruct ifstream obj error" << endl;exit(EXIT_FAILURE);}int length; ifs.seekg(0, ifs.end);length = ifs.tellg();ifs.seekg(0, ifs.beg);            //回到开头了cout << "file_size: " << length << endl;ifs.close();return 0;
}

五. 从C语言的 fprintf 进化到 sstream  实现序列化和反序列化

  • 首先刨析一下  sprintf  +  sscanf

代码测试:

//案例1
int main() {int a = 10;char s[5] = "abc";char buff[20] = { 0 };sprintf(buff, "%d %s", a, s); //序列化a = 100;s[0] = 'c';sscanf(buff, "%d %s", &a, s);   //反序列化还原cout << a << " " << s << endl;while (1);return 0;
}
//案例2:
/*
int main ()
{char sentence []="Rudolph is 12 years old";char str [20];int i;sscanf (sentence,"%s %*s %d",str,&i);printf ("%s -> %d\n",str,i);return 0;
}
*/
  • C++ 中的 序列化  和  反序列化 (针对这个:专门设置了一个字符串流类)  string streams 字符串流

既然是流所以还是支持流式的数据流入和流出的.....     测试代码如下:

int main() {stringstream ss;int age = 20;char name[20] = "张三";ss << age <<"\t"<< name;//先流入到 ss 中去age = 100;strcpy(name, "12345");    //先改一下 这样后面才知道是不是流出了数据的ss >> age >> name;cout << "age: " << age << " " << "name: " << name << endl;return 0;
}

从一道实例题目上手:  序列化和反序列化二叉树

剑指 Offer II 048. 序列化与反序列化二叉树

class Codec {
public:// Encodes a tree to a single string.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实现的  序列化和反序列化

上述仅个人的学习C和 C++的一个笔记小结, 很多是个人看法和用法, 如有不足或者错误之处欢迎大家改正, 祝看本文的人一切顺利,共同进步   (内容简单, 但书写不易, 如果觉得有帮助, 希望点赞支持, 三连缘分)

C语言, C++ IO 总结. 一篇文章帮你透析缓冲区存在的意义, C, C++ IO的常见用法相关推荐

  1. 一篇文章帮你搞定JVM中的堆

    文章目录 一篇文章帮你搞定JVM中的堆 堆的核心概述 堆的内存细分 设置堆内存大小与OOM OOM(OutOfMemory)举例 年轻代与老年代 图解对象分配过程 MinorGC,MajorGC,Fu ...

  2. 小程序开发教程,字节跳动Android三面凉凉,一篇文章帮你解答

    开篇 说一下我大概的情况.渣本毕业,工作已经有快3年了,从高中就开始玩小破站.无论是学习还是日常放松都是在b站.大学主学的软件技术专业,所以,入职bilibili是我大学时期给自己定的小目标. 在学校 ...

  3. 一篇文章帮你彻底搞清楚“I/O多路复用”和“异步I/O”的前世今生

    来源:微信公众号[编程新说] 曾经的VIP服务 在网络的初期,网民很少,服务器完全无压力,那时的技术也没有现在先进,通常用一个线程来全程跟踪处理一个请求.因为这样最简单. 其实代码实现大家都知道,就是 ...

  4. C语言从零开始——学这一篇文章就够了

    这个假期重新回顾了之前这个<C语言从零开始>的系列.当时由于没有整体规划,想到哪儿写到哪儿,导致了里面的文章质量不够统一.于是,我又对里面的部分文章做了些调整,力求整体脉络更加连贯. 后面 ...

  5. 我想谈谈关于Android面试那些事,一篇文章帮你解答

    开头 通常作为一个Android APP开发者,我们并不关心Android的源代码实现,不过随着Android开发者越来越多,企业在筛选Android程序员时越来越看中一个程序员对于Android底层 ...

  6. 意外收获字节跳动内部资料,一篇文章帮你解答

    前言 俗话说"生于忧患,死于安乐",其实大部分中年危机,就是在安乐中产生的. 有的人或许会反驳,"照你这么说,我还必须奋斗了,不奋斗就要死,难道选择安逸的生活就不对吗?我 ...

  7. 【干货分享】一篇文章帮你搞定前端高频面试题

    前言 如今前端技术日新月异.对于前端开发人员来说,不仅需要掌握最新的前沿技术,还需要保持对基础知识的熟练掌握.而面试则是进入优秀企业的必经之路.在面试中,高频面试题的掌握是获得成功的关键.本文将为大家 ...

  8. 【干货】你头秃都没想到还能这样吧!一篇文章帮你解答

    前言 抱着侥幸心理投了字节跳动后台JAVA开发岗,居然收到通知去面试,一面下整个人来都是懵逼的,不知道我对着面试官都说了些啥(捂脸~~).侥幸一面居然过了,三天后接到二面通知,结果这次不再幸运,败在数 ...

  9. android适配布局,大佬手把手教你如何仿写出大厂的APP,一篇文章帮你解答

    前言 程序员,近年来十分火爆的职业,凭着巨大的市场缺口和高额的薪水吸引着大量毕业生加入程序员的队伍.这其中就包括各类专业的学生,像我这种自动化专业的也在其内.这些不是计算机科班出身的可以看作是半路出家 ...

最新文章

  1. HTTP服务器端常用推送技术
  2. Asp.net core 学习笔记 ( Web Api )
  3. java基础篇之理解synchronized的用法
  4. Python 入门篇-python3和python2的差异总结
  5. Pytorch学习 - 保存模型和重新加载
  6. 斐波那契数列python递归 0、1、1、2、3_python: 递归和递推方法求斐波那契数列
  7. nodeJS 的 path.resolve() 用法解析
  8. jvm gc停顿_在JVM中记录世界停顿
  9. 红旗linux怎么更新,红旗linux7.0下自动更新firefox
  10. 【uoj207】 共价大爷游长沙
  11. 南阳理工oj 题目26 孪生素数问题 素数筛选法
  12. IT 已成为最疯狂的加班行业,没有之一
  13. JavaWeb项目架构之Kafka分布式日志队列
  14. 五子棋游戏代码(完整版)
  15. scikit-learn功能大全
  16. 测试象棋水平用哪个软件好,最新象棋软件作弊名单公布,软件测试员都被封,哪些网络象棋主播...
  17. 理解 Mach-O 并提高程序启动速度
  18. SVN各个状态:A C D M G U R I具体含义
  19. Laravel 使用 Entrust 实现 RBAC
  20. 微信开发者平台应用创建

热门文章

  1. 摄像头图像测试1-基本概念
  2. MCU端 Boot+App设计方案
  3. vue拖拽组件生成页面代码,vue可视化拖拽组件模板
  4. 为什么IDEA比Eclipse更好
  5. 主题:我对颈椎问题之研究与实践
  6. 【题解】【蓝桥杯】试题 历届真题 砝码称重【第十二届】【省赛】【B组】
  7. vue props对象validator自定义函数
  8. 深度强化学习系列(15): TRPO算法原理及Tensorflow实现
  9. 验房师去哪里找靠谱?房屋验收需要验房师吗?
  10. 流量卡实物商城系统源码