【与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.xdnf.cn/news/143700.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

4.C++面向对象1(类的定义,实例化,三大特性-封装)

⭐本篇文章为C学习第4篇&#xff0c;主要了解类和对象基础 ⭐本人C代码的Gitte仓库&#xff1a;yzc的c学习: 小川c的学习记录 - Gitee.com 、 ⭐我们知道面向对象有三大特性&#xff1a;封装&#xff0c;继承&#xff0c;多态&#xff0c;我们以类为基础进行…

linux hadoop-3.3.6 hbase-2.5.7

软件下载 hadoop https://dlcdn.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz 可以直接下载到本地&#xff0c;也可以直接下载进虚拟机中 如果速度较慢&#xff0c;可以用&#xff1b;另一个 wget https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common…

模电模块(一)

这个看起来功能挺全的&#xff0c;就是小贵&#xff0c;有时间自己做一个&#xff1a; 首页-康威科技-淘宝网 (taobao.com) 画一个集成板&#xff0c;集合上述模块的功能。

kubernetes架构

kubernetes cluster由master和node组成&#xff0c;节点上运行着若干kubernetes服务Master节点&#xff1a; master是kubernetes cluster的大脑&#xff0c;运行着的Daemon服务包括kube-apiserver&#xff0c;kube-scheduler,kube-controller-manager&#xff0c;etcd和Pod网络…

VBS学习1 - 语法、内置函数、内置对象

文章目录 概述执行脚本语法转义字符文本弹框msgbx定义变量dim&#xff08;普通类型&#xff09;定义接收对象set字符拼接&用户自定义输入框inputbox以及输入判断ifelse数组&#xff08;参数表最大索引&#xff0c;非数组容量&#xff09;有容量无元素基于元素确定容量 循环…

tidb 集群搭建

官网的搭建文档&#xff1a;使用 TiUP 部署 TiDB 集群 | TiDB 文档中心 我本地使用三台 centos7.9 服务器搭建&#xff0c;要保证三台服务器之间是可以互相通信的&#xff1b; 搭建集群的命令在其中一台服务器上执行即可&#xff1b; 1、安装tiup&#xff1a; curl --proto …

【接口测试】Postman--变量与集合

一、变量 ​ 变量这个概念相信大家都不陌生&#xff0c;因此在这里我们不介绍了。主要说一下在Postman中有哪几类变量&#xff0c;主要包括以下四类&#xff1a; Global&#xff08;全局&#xff09; Environment&#xff08;环境&#xff09; Local&#xff08;本地&#xf…

[深度学习]Pytorch框架

1 深度学习简介 应用领域&#xff1a;语音交互、文本处理、计算机视觉、深度学习、人机交互、知识图谱、分析处理、问题求解 2 发展历史 1956年人工智能元年2016年国内开始关注深度学习2017年出现Transformer框架2018年Bert和GPT出现2022年&#xff0c;chatGPT出现&#xff0…

SHL笔试测评系统题库考什么?如何通过综合测评|附性格测试104道

嘿&#xff0c;各位求职小伙伴们&#xff01;我是职小豚&#xff0c;今天就来带大家深入了解神秘又充满挑战的 SHL 笔试测评系统。 一、SHL 人才测评系统介绍 SHL 呀&#xff0c;那可是人才测评领域的超级大明星&#xff01;就像一个智慧的魔法师&#xff0c;用各种神奇的题目…

ICP算法介绍,机器人姿态估计,三维点云配准

介绍 ICP算法&#xff0c;即Iterative Closest Point&#xff08;迭代最近点&#xff09;算法&#xff0c;是一种广泛应用于计算机视觉和图像处理领域的几何配准算法。它的主要目的是通过最小化两组点集之间的距离来找出一组变换&#xff0c;使得两组点集尽可能地对齐。ICP算法…

CDN方式的vant组件不能用,是因为标签要补成双标签

cdn方式的标签需要时双标签&#xff0c;单标签不能用 <van-fieldreadonlyclickable:value"formdata.yuyue_changguan"label"预约场馆"placeholder"点击选择预约场馆"click"showPicker true"></van-field><van-popup v…

spring springboot 日志框架

一、常见的日志框架 JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j.... 注意&#xff1a;SLF4j 类似于接口 Log4j &#xff0c;Logback 都是出自同一作者之手 JUL 为apache 公司产品 Spring&#xff08;commons-logging&#xff09;、Hibernate&#xff08;jboss…

配置环境-keil

配置keil -- 先将keil安装配置好&#xff0c;包括库 一、STM32 -- STM32是意法半导体&#xff08;意大利&#xff09;采用ARM公司设计的内核&#xff0c;设计一系列32位单片机芯片。 1、STM32开发的几种方式 2、STM32寄存器和库函数版本的工程创建 新建文件夹 复制相关文件…

Vmware虚拟机无法打开内核设备“\\.\Global\vmx86“的解决方法

我的问题是在一次系统更新后&#xff0c;导致虚拟机无法使用的。我的虚拟机只有方法三解决了问题。 一、方法一 以管理员身份打开cmd&#xff0c;依次执行以下命令&#xff1a; net start vmci net start vmx86 net start VMnetuserif二、方法二 按 WinR 键&#xff0c;运行…

文件上传-php

查找方式 ***(1) 黑盒 查找(upload) 扫描 (2) 应用型 窗口 上传中心或者后台中心 上传 Ps:后台是后台 权限是权限 (3) 会员中心 (4) 白盒 基本函数定义 写前端的 Enctype 上传类型Method 提交方式Onsubmit 鼠标的时间Action"放在指定文件"Php 接受表单数据 isset(…

macOS平台TensorFlow环境安装

1.安装xtarfile pip3 install xtarfile 2.安装 pip3 install matplotlib 3.安装jieba pip3 install jieba 4.安装 pip3 install tensorflow tensorflow安装成功

多目标优化算法(Multi-Objective Optimization Algorithms, MOOA)介绍

在现实世界中&#xff0c;许多问题都涉及到多个目标的权衡和优化。例如&#xff0c;在工程设计中&#xff0c;可能需要同时考虑成本、效率和可靠性&#xff1b;在资源管理中&#xff0c;可能需要平衡环境保护和经济效益。多目标优化算法&#xff08;Multi-Objective Optimizati…

JavaEE:网络编程(套接字)

文章目录 Socket套接字TCP和UDP的区别有连接/无连接可靠传输/不可靠传输面向字节流/面向数据报全双工/半双工 UDP/TCP api的使用UDPDatagramSocketDatagramPacketInetSocketAddress练习 TCPServerSocketSocket练习 Socket套接字 Socket是计算机网络中的一种通信机制&#xff0…

内卷、同质化严重,储能的创新在哪里?一文盘点行业最新技术方向。

一、市场现状介绍 1、储能企业的三大挑战 价格战愈演愈烈&#xff1a;今年以来&#xff0c;储能系统价格一路走低&#xff0c;从年初的0.8元/Wh降至如今的0.5元/Wh&#xff0c;降幅超过30%。这样的价格战让不少企业倍感压力。 产品同质化严重&#xff1a;纵观2024年上半年的…

C#学习(四)C#连接Mysql实现增删改查

博主刚开始接触C#&#xff0c;本系列为学习记录&#xff0c;如有错误欢迎各位大佬指正&#xff01;期待互相交流&#xff01; 文章目录 一、安装Mysql1.1 启用Mysql1.2 登录Mysql 二、安装Navicat2.1 建立连接2.2 新建数据库2.3 新建表 三、创建Winform实现增、删、改、查3.1 下…