【与C++的邂逅】--- C++的IO流

 Welcome to 9ilk's Code World

       

(๑•́ ₃ •̀๑) 个人主页:        9ilk

(๑•́ ₃ •̀๑) 文章专栏:     与C++的邂逅  


本篇博客我们来了解C++中io流的相关知识。


🏠 C语言输入输出

C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。注意宽度输出和精度输出控制。C语言借助了相应的缓冲区来进行输入与输出。如下图所示:

对输入输出缓冲区的理解 :

1. 可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分差异,可以很容易写出可移植的程序

2. 可以使用这部分的内容实现"行"读取的行为,对于计算机而言是没有“行"这个概念的,有了这部分,就可以定义”行"的概念,然后解析缓冲区的内容,返回一个“行"。

🏠 流是什么

流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据( 其单位可以是bit,byte,packet )的抽象描述。

C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为"流"。

C++流的特性 : 有序连续,具有方向性。

为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能。

🏠 C++IO流

C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或间接派生自ios类。

📌 C++标准IO流

C++标准库提供了4个全局流对象cin,cout,cerr,clog:

1. cout : 用来进行标准输出,即数据从内存流向控制台(显示器)。

2. cin : 用来进行标准输入即数据通过键盘输入到程序中

3. cerr : 用来进行标准错误的输出。

4. clog : 用来进行日志的输出。

cout << "1111" << endl; //1111
cerr << "1111" << endl; //1111
clog << "1111" << endl; //1111 

注 :

1. cout,cerr,clog是ostream类的三个不同对象,这三个对象基本用法没有什么区别,只是应用场景不同。

2. 使用这4个全局流对象必须包含头文件<iostream>并引入std标准空间。

  • cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完之后,才要求输入新的数据
int a = 0, b = 0;
cin >> a; //输入:10 20
cout << a << endl;
cin >> b; //直接从输入缓冲区提取
cout << b << endl;
  • 空格和回车都可以作为数据之间的分隔符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不可能有空格。回车符也无法读入。
string s;
cin >> s;          //输入:"hello world"
cout << s << endl; //输出:"hello"

对于含有空格的字符串,我们需要使用getline函数进行读取,因为getline函数只有遇到’\n’才会停止读取。

string s;
getline(cin, s);   //输入:"hello world"
cout << s << endl; //输出:"hello world"
  • cin和cout可以直接输入和输出内置类型数据,原因:标准库已经将所有内置类型的输入和输出全部重载了。

>>运算符:

<<运算符:

  • 对于自定义类型,如果需要支持cin和cout的标准输入输出,需要对<<和>>进行重载。
  • 在线OJ中的输入和输出:

      对于IO类型的算法一般都需要循环输入;输出时应该严格按照题目要求进行,多一个少一个空格都不行;连续输入时,vs系列编译器下在输入ctrl+z时结束。

// 单个元素循环输入
while(cin>>a)
{
// ...
}
// 多个元素循环输入
while(c>>a>>b>>c)
{
// ...
}
// 整行接收
while(cin>>str)
{
// ...
}
  • istream类型对象转换为逻辑条件判断值
string str;
while(cin >> str)
{cout << str << endl;
}

对于这段连续输入输出的代码如果我们想结束只需要ctrl+z,那为什么ctrl+z可以结束呢?

stream& operator>> (int& val);
explicit operator bool() const;

实际上我们看到使用while(cin >> str)去流中提取对象数据时,调用的是operator>>,返回值是istream类型的对象,但是istream对象是不可以做逻辑条件值的,源自于istream的对象又调用了operator bool,operator bool调用时如果接收流失败,或者有结束标志,则返回false。

while(opertor<<(cin,str).operator bool())
{cout << str << endl;
}

📒 关于标志

由文档可知 , 当failbit标志或badbit标志都没有被设置之后才返回true,否则返回false。那什么是标志呢?

由文档可知:

1.eof表示已经达到文件尾。

2.good是表示流状态完全正常,没有任何错误。

3.badbit表示输入输出流发生了不可恢复的错误,当这个标志被设置时,意味着流的状态已损坏,后续的输入输出操作可能无法正常进行。注意:这里是可能,意思是这个标志被设置后后面继续使用可能会出现问题,并不是设置完后流中的内容立即失效或者不可访问。

4.fail表示发生了可恢复的错误,比如类型不匹配或格式错误,流仍然可以继续使用。

对于ctrl+z相当于是设置了failbit标志:

我们可以用good(),eof(),fail(),bad()这几个成员函数来帮助我们读取这几个标志的状态。

string str;
while(operator<<(cin,str).operator bool())
{cout << cin.good() << endl;cout << cin.eof() << endl;cout << cin.bad() << endl;cout << cin.fail() << endl;cout << str << endl;
}cout << cin.good() << endl;cout << cin.eof() << endl;cout << cin.bad() << endl;cout << cin.fail() << endl;

运行结果:

311123//输入

1

0

0

0

311123//输出

^z //ctrl + z

0

1

0

1

注:我们可以把输入设备和输出设备当作文件,此时ctrl+z之后流提取结束相当于文件结束,所以还把eof标志设置了。

如果想正常提取那就需要只有good标志被设置,否则不能正常流提取;此时我们可以用clear()标志进行。

string str;
while(operator<<(cin,str).operator bool())
{cout << cin.good() << endl;cout << cin.eof() << endl;cout << cin.bad() << endl;cout << cin.fail() << endl;cout << str << endl;
}cout << cin.good() << endl;
cout << cin.eof() << endl;
cout << cin.bad() << endl;
cout << cin.fail() << endl;cin.clear();
cin >> str;
  • 输入的数据类型必须要与提取的数据类型一致,否则出错。出错只是在对应流的标志状态设置为1
int i = 0;
cin >> i ;
cout << i << endl;cin >> i;
cout << i << endl;cout << cin.good() << endl;
cout << cin.eof() << endl;
cout << cin.bad() << endl;
cout << cin.fail() << endl;

11s//输入

11 //第一次打印

0//第二次

注 :我们知道我们输入内容都在缓冲区里,此时第二次提取遇到字符出错,整形无法正确提取,i被默认清为0。

int i = 0;
cin >> i ;
cout << i << endl;cin >> i;
cout << i << endl;cin.clear();
cin >> i;
cout << cin.good() << endl;
cout << cin.eof() << endl;
cout << cin.bad() << endl;
cout << cin.fail() << endl;

clear之后:

0

0

0

1

为什么clear之后fail标志还是被设置呢?那是因为clear只改变标志的状态,而字符s还在缓冲区内,下次读取还会出错,因此我们需要把缓冲区内的字符拿掉

正确读取数据的程序:

int i = 0;
cin >> i ;
cout << i << endl;cin >> i;
cout << i << endl;cin.clear();
cin >> i;
while (cin.fail())
{cin.clear();cin.get();//不断拿掉字符cin >> i;
}
  • cin和cout的效率问题

在io需求比较高的地方,如部分大量输入的竞赛题中,加上以下3行代码可以提高C++IO效率.

ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout,tie(nullptr);

解释:

1. 缓冲区本质是提高效率,但是C++兼容了C语言的stdio流确保printf打印时数据在缓冲区的刷新,此时两种语言的流就需要保持同步刷新,这需要一些时间代价,第一行代码相当于取消同步刷新.

2.默认cin和cout是绑定的,也就是一个流IO操作时另一个绑定的流也同步刷新,后两行代码相当于取消绑定.

📌 C++标准文件流

C++根据文件的内容的数据格式分为二进制文件和文本文件,采用文件流对象操作文件的一般步骤如下:

📒 定义一个文件流对象

对应操作场景
ifstream只读
ofstream只写
fstream可读可写

注:使用文件流对象需要包含对应的头文件<fstream>

📒 使用文件流对象成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系

                              打开方式                            功能 
                                  in                      以读的方式打开文件     
                                 out                      以写的方式打开文件
                               binary                  以二进制的方式打开文件
                                  ate                 输出位置从文件的末尾开始
                                  app               以追加的方式对文件进行写入
                                 trunc                先将文件内容清空再打开文件

类似C语言fopen我的流对象可以使用open这个成员函数进行打开文件,参数一是所要打开的文件,参数二是打开文件的方式。 

注 :

1. 注意这几种不同的打开方式是可以用运算符 | 进行结合的,因为在底层这些打开方式的是用一个整数的bit位来存储表示的,因此或一下不同mod对应位置都设置为1。

fstream fs;
fs.open("data.txt",ofstream::out | ofstream::binary); //两种方式打开

2.使用ofstream类对象的open函数时,若不指定打开方式,则默认以写的方式打开文件

3.使用ifstream类对象的open函数时,若不指定打开方式,则默认以读的方式打开文件。

4.使用fstream类对象的open函数时,若不指定打开方式,则默认以写+读的方式打开。

📒 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写

成员函数功能
put插入一个字符到文件
write插入一段字符到文件
get从文件提取单个字符
 read 从文件提取多个字符
tellg获取当前字符在文件当中的位置
seekg设置对文件进行操作的位置
>>运算符重载将数据形象地以"流"的形式进行输入
<<运算符重载将数据形象地以"流"的形式进行输出

我们建议使用<<和>>运算符对文件进行操作,因为这很方便符合我们平时的输入输出。

对文件进行写入:

void WriteFile()
{ofstream ofs("text.txt"); //定义文件流对象打开文件并写ofs << "hello zhuang"; //字符串流入文件ofs.close(); //关闭文件
}

对文件进行读取:

void ReadFile()
{ifstream ifs("text.txt"); //定义流对象 打开文件并读char data[100];ifs >> data; //文件数据"流入"字符串dataifs.close(); //关闭文件
}

注 : 可以在定义流对象的同时指定要打开的文件名,以及文件的打开方式。

📒 关闭文件

void close();

以二进制的形式对文件操作:

1. 以二进制形式对文件进行写入

void WriteBin()
{ofstream ofile;ofile.open("data.bin",ofstream::out | ofstream::binary); //二进制方式写入char data[] = "hello world";ofile.write(data,strlen(data));//将data写入文件ofile.put('!');ofile.close();
}

2.以二进制形式对文件进行读取

void ReadBin()
{ifstream ifile;ifile.open("data.bin",ifstream::in | ifstream::binary);//二进制读取ifile.seekg(0,ifile.end); //跳转到文件末尾int length = ifile.tellg(); //获取当前字符正在文件中的位置,即文件字符总数ifile.seekg(0,ifile.beg);char data[100];ifile.read(data.length);//将数据从文件写入dataifile.close(); 
} 

以文本形式操作文件 :

1. 以文本形式对文件进行写入操作:

void WriteText()
{ofstream ofile;ofile.open("data.txt");//默认以写方式打开char data[] = "hello world";ofile.write(data,strlen(data));ofile.put('!');ofile.close(); 
}

2.以文本形式对文件进行读取操作:

void ReadText()
{ifstream ifile;ifile.open("data.txt");//二进制读取ifile.seekg(0,ifile.end); //跳转到文件末尾int length = ifile.tellg(); //获取当前字符正在文件中的位置,即文件字符总数ifile.seekg(0,ifile.beg);char data[100];ifile.read(data.length);//将数据从文件写入dataifile.close(); 
} 

🏠 stringstream的简单介绍

📌 C语言中整形转字符串

在C语言中,如果想要将一个整形变量的数据转化为字符串格式,主要有两种方式:

1. 使用itoa()函数

2. 使用sprintf()函数

int main()
{int n = 2310123;char s1[32];_itoa(n,s1,10);char s2[32];sprintf(s2,"%d",n);return 0;
}

注意 : 这两个函数在转化时,都得需要先给出保存结果的空间,空间大小不好界定,而且转化格式不匹配时,可能还会得到错误的结果甚至程序崩溃。

📌 C++stringstream对象

在C++中可以使用stringstream类对象来避开此问题。在程序中如果想要使用stringstream,必须要包含头文件<sstream>。

操作场景
ostringstream输出操作
istringstream输入操作
stringstream输入+输出操作

📒 stringstream主要用处

1. 将数值类型转换为字符串

int a = 10;
stringstream ss;
//使用流插入流提取
ss << a << endl;
string s;
ss >> s;
cout << "s : " << s << endl;
//使用底层str
double d = 1.2;
ss << d << endl;
cout << ss.str() << endl;
s = ss.str();
cout << "s : " << s << endl;

2. 字符串拼接

stringstream sstream;
// 将多个字符串放入 sstream 中
sstream << "first" << " " << "string,";
sstream << " second string";
cout << "strResult is: " << sstream.str() << endl;
// 清空 sstream
sstream.str("");
sstream << "third string";
cout << "After clear, strResult is: " << sstream.str() << endl;

3.序列化和反序列化结构数据

序列化:结构信息转成字符串。

反序列化:字符串转化成信息。

struct ChatInfo
{string _name; // 名字int _id; // idDate _date; // 时间string _msg; // 聊天信息
};
int main()
{// 结构信息序列化为字符串ChatInfo winfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧"};ostringstream oss;oss << winfo._name << " " << winfo._id << " " << winfo._date << " "<< winfo._msg;string str = oss.str();cout << str << endl<<endl;// 我们通过网络这个字符串发送给对象,实际开发中,信息相对更复杂,// 一般会选用Json、xml等方式进行更好的支持// 字符串解析成结构信息ChatInfo rInfo;istringstream iss(str);iss >> rInfo._name >> rInfo._id >> rInfo._date >> rInfo._msg;cout << "-------------------------------------------------------"<< endl;cout << "姓名:" << rInfo._name << "(" << rInfo._id << ") ";cout <<rInfo._date << endl;cout << rInfo._name << ":>" << rInfo._msg << endl;cout << "-------------------------------------------------------"<< endl;return 0;
}

提取字符串流对象信息两种方式:

1. 直接使用流提取流插入

2. 利用底层str来构造流对象从而提取转换的信息或者直接将信息用来构造流对象或者用字符串信息来构造流对象的底层str从而提取信息

class Date
{friend ostream& operator << (ostream& out, const Date& d);friend istream& operator >> (istream& in, Date& d);
public:Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){}operator bool(){// 这里是随意写的,假设输入_year为0,则结束if (_year == 0)return false;elsereturn true;}
private:int _year;int _month;int _day;
};istream& operator >> (istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}ostream& operator << (ostream& out, const Date& d)
{out << d._year << " " << d._month << " " << d._day;return out;
}int main()
{int i = 123;Date d = {2024,9,18};//方式一使用<<和>>stringstream ss1;ss1 << i << endl;ss1 << d << endl;int j = 0 ;Date x;ss1 >> j >> x;//使用底层string对象string str = ss1.str(); stringstream ss2(str);//也可以"123\n2024 9 18"直接构造对象//也可以stringstream ss3;ss3.str(str);//输出给j和x...return 0;
}

注 : 这里能正确提取到数据是因为我们在转换数据成字符串时用换行符和空格进行数据分隔符,因此能正确分隔;如果数据格式对不上,此时需要跟之前一样清理流标志(clear)并且用get等拿掉非法字符。

stringstream对象总结:

1. stringstream对象实际是在底层维护了一个string对象用来保存结果。

2.构造stringstream对象可以直接用字符串/对象构造,或者构造其底层str。

3.多次数据类型转化时,流的状态标志bad,eof,fail可能被设置从而导致后续操作失败,因此在进行下一次转换时必须调用clear()将状态重置为goodbit才可以进行转换,但是clear()不会将底层string对象清空。

4.可以使用s.str("")将底层string对象清空,否则多次转换时,会将结果全部积累在底层string对象。

string  ret;
stringstream ss;
ss << "2024" << "zhuang";
ss >> ret;	
cout << "下一次转换" << endl;//2024zhuang
//清空状态和string
ss.clear();
ss.str("");
ss << "Thanks" << "reading";
cout << ss.str() << endl;
ret = ss.str();
cout << ret << endl; //Thanksreading

5.获取数据转换后结果有两个方法:(1) 使用>>运算符从流当中提取。(2)使用底层str获取。

6.stringstream使用string类对象替代字符数组,可以避免缓冲区溢出的风险,而且对参数类型进行推演,不需要进行格式化控制,也不会存在格式化失败的风险,因此使用更方便,更安全,但提取时注意数据分隔符的使用。


总结:

本篇博客我们讲解了三个C++IO流:C++标准IO流,C++标准文件流,stringstream,同时讲解三个流读写的相关操作以及一些细节。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/53074.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文解读《LaMP: When Large Language Models Meet Personalization》

引言&#xff1a;因为导师喊我围绕 “大语言模型的个性化、风格化生成” 展开研究&#xff0c;所以我就找相关论文&#xff0c;最后通过 ACL 官网找到这篇&#xff0c;感觉还不错&#xff0c;就开始解读吧&#xff01; “说是解读&#xff0c;其实大部分都是翻译哈哈哈&#x…

系统安全设计规范(Word完整版)

1.1 总体设计 1.1.1 设计原则 1.2 物理层安全 1.2.1 机房建设安全 1.2.2 电气安全特性 1.2.3 设备安全 1.2.4 介质安全措施 1.3 网络层安全 1.3.1 网络结构安全 1.3.2 划分子网络 1.3.3 异常流量管理 1.3.4 网络安全审计 1.3.5 网络访问控制 1.3.6 完整性检查 1.…

Cpp类和对象(上)(3)

文章目录 前言一、面向过程与面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及类的封装类的访问限定符类的封装 五、类的作用域(类域)六、类的实例化七、类对象模型如何计算类对象的大小类对象的存储方式猜测 八、this指针this指针的引出this指针的特性 九、C语言…

1×1卷积核【super star 卷积核】

一、11卷积的作用 我们先来给出11卷积的一般作用&#xff0c;如下所示&#xff1a; • 跨通道的特征整合 • 特征通道的升维与降维 • 减少权重参数&#xff08;卷积核参数&#xff09; 【 简化模型 】 1.1 特征通道的升维与降维/跨通道的特征整合/简化模型 输入数据&…

Node.js 多版本安装与切换指南

一.使用nvm的方法 1. 卸载nodejs 如果你的电脑有安装nodejs&#xff0c;需要先卸载掉&#xff1b;若没有请直接下一步。 2. 前往官网下载nvm nvm&#xff1a;一个nodejs版本管理工具&#xff01; 官网地址&#xff1a;nvm文档手册 - nvm是一个nodejs版本管理工具 - nvm中文…

Oracle数据恢复—Oracle数据库误删除表数据如何恢复数据?

删除Oracle数据库数据一般有以下2种方式&#xff1a;delete、drop或truncate。下面针对这2种删除oracle数据库数据的方式探讨一下oracle数据库数据恢复方法&#xff08;不考虑全库备份和利用归档日志&#xff09;。 1、delete误删除的数据恢复方法。 利用oracle提供的闪回方法…

简单题21 - 合并两个有序链表(Java)20240917

问题描述&#xff1a; java代码&#xff1a; /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val…

【DAY20240918】03教你轻松配置 Git 远程仓库并高效推送代码!

文章目录 前言 git diff一、远程仓库&#xff1f;1、在 Gitee 上新建仓库&#xff1a;2、Git 全局设置&#xff1a;3、添加远程仓库&#xff1a;4、推送本地代码到远程仓库&#xff1a;5、输入用户名和密码&#xff1a;6、后续推送&#xff1a; 二、全情回顾三、参考 前言 git …

二十种编程语言庆祝中秋节

二十种编程语言庆祝中秋节 文章目录 二十种编程语言庆祝中秋节中秋快乐&#xff01;家人们 &#x1f973;一 Python二 C三 C四 Java五 C#六 Perl七 Go八 Asp九 PHP十 JavaScript十一 JavaScript HTML十二 Visual Basic十三 早期 VB十四 Visual C十五 Delphi十六 Shell十七 Cobo…

场外个股期权通道商是什么业务?个人投资者可以参与场外期权吗?

今天带你了解场外个股期权通道商是什么业务&#xff1f;个人投资者可以参与场外期权吗?场外个股期权通道商在个股期权市场中起着重要的中介作用&#xff0c;提供定制化的交易服务和风险管理解决方案。 场外个股期权通道商 场外个股期权通道商是一种金融机构&#xff0c;主要…

15.10 在k8s部署grafana-deployment并导入k8s大盘

本节重点介绍 : grafana deployment部署k8s大盘导入 准备yaml 部署工作 1. 修改yaml中的节点选择器标签 k8s-node01改为你自己的节点 2. 在节点上创建数据目录 mkdir -pv /data/grafana3. 部署grafana # 部署 kubectl apply -f deployment.yaml # 检查 [rootprome-mast…

OpenCV高阶操作

在图像处理与计算机视觉领域&#xff0c;OpenCV&#xff08;Open Source Computer Vision Library&#xff09;无疑是最为强大且广泛使用的工具之一。从基础的图像读取、 1.图片的上下&#xff0c;采样 下采样&#xff08;Downsampling&#xff09; 下采样通常用于减小图像的…

1. 运动控制指令概要(omron 机器自动化控制器)

机器自动化控制器——第一章 运动控制指令概要 1-1 运动控制指令PLCopen运动控制用功能块运动控制指令概要▶ 运动控制指令的种类▶ 状态变化▶ 运动控制指令的启动和状态▶ 异常处理▶ 执行运动控制指令时输入变量的变更(指令重启)▶ 通过选择缓存模式执行指令多重启动▶ 通过…

python画图|中秋到了,尝试画个月亮(球体画法)

学习了一段时间的画图&#xff0c;已经掌握了一些3D图的画法&#xff0c;部分链接如下&#xff1a; python画图|极坐标下的3D surface-CSDN博客 python画图|3D参数化图形输出-CSDN博客 我们今天尝试一下月亮的画法。 【1】官网教程 首先还是到达官网教程学习&#xff1a; …

Mina protocol - 体验教程

Mina protocol - 体验教程 一、零知识证明( Zero Knowledge Proof )1、零知识证明&#xff08;ZKP&#xff09;的基本流程工作流程&#xff1a; 2、zkApp 的优势&#xff1a;3、zkApp 每个方法的编译过程&#xff1a; 二、搭建第一个zkapp先决条件1、下载或者更新 zkApp CLI​2…

黑神话悟空+云技术,游戏新体验!

近期&#xff0c;一款名为黑神话悟空的游戏因其独特的艺术风格和创新的技术实现在玩家中产生了不小的影响。 而云桌面技术作为一种新兴的解决方案&#xff0c;正在改变人们的游戏体验方式&#xff0c;使得高性能游戏可以在更多设备上流畅运行。 那么&#xff0c;黑神话悟空如…

Hazel 2024

不喜欢游戏的人也可以做引擎&#xff0c;比如 cherno 引擎的作用主要是有两点&#xff1a; 将数据可视化交互 当然有些引擎的功能也包含有制作数据文件&#xff0c;称之为资产 assets 不做窗口类的应用栈&#xff0c;可能要花一年才能做一个能实际使用的应用&#xff0c;只需…

VSCode扩展连接虚拟机MySQL数据库

在虚拟机安装MySQL vscode通过ssh远程登录Ubuntu 在vscode终端运行以下命令。 sudo apt-get install mysql-server-5.7 用以下命令确认MySQL是否安装完成。 sudo mysql MySQL安装成功。 在VSCode安装SQL扩展 扩展名&#xff1a;MySQL Shell for VS Code。 安装完成后&am…

JavaScript高级——闭包的作用

1、使用函数内部的变量在函数执行完后&#xff0c;仍然存活在内存中&#xff08;延长了局部变量的生命周期&#xff09; 2、让函数外部可以操作&#xff08;读写&#xff09;到函数内部的数据&#xff08;变量/函数&#xff09; 3、函数执行完后&#xff0c;函数内部声明的局…

使用原生HTML的drag实现元素的拖拽

HTML 拖放&#xff08;Drag and Drop&#xff09;接口使应用程序能够在浏览器中使用拖放功能。例如&#xff0c;用户可使用鼠标选择可拖拽&#xff08;draggable&#xff09;元素&#xff0c;将元素拖拽到可放置&#xff08;droppable&#xff09;元素&#xff0c;并释放鼠标按…