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

C++学习路线(二十八)

项目二

某无线通信设备ODU设备, 具有以下功能:

        查看发射功率, 设置发射功率
        查看发射频率, 设置发射频率
        查看带宽, 修改带宽,
        查看设备概述(各指标的值).

ODU.h

#pragma once
#include <string>
class ODU {
public:
	ODU();
	~ODU();
	float getTxPower(); // 发射功率
	int getTxFreq(); // 发射频率
	float getBrandWidth(); // 带宽

	bool setTxPower(float power); // 设置发射功率
	bool setTxFreq(int frequency); // 设置发射频率
	bool setBandWidth(float bandWidth); // 设置
	std::string description();
protected:
	float txPower; // 发射功率
	int txFreq; // 发射频率
	float bandWidth; // 带宽
};

ODU.cpp

#include "ODU.h"
#include <sstream>
using namespace std;
ODU::ODU(){}
ODU::~ODU(){}
float ODU::getTxPower() {
	return txPower;
}

bool ODU::setTxPower(float power) {
	txPower = power;
	return true;
}

int ODU::getTxFreq() {
	return txFreq;
}
float ODU::getBrandWidth() {
	return bandWidth; // 带宽
}

bool ODU::setTxFreq(int frequency) {
	txFreq = frequency;
	return true;
}
bool ODU::setBandWidth(float bandWidth) {
	bandWidth = bandWidth;
	return true;
}
std::string ODU::description() {
	stringstream ss;
	ss << "ODU: txPower=" << txPower << ", txFreq=" << txFreq << ", bandWidth=" << bandWidth;
	return ss.str();
}

后来对该产品做了升级, 研发了ODU330产品:
 
这个产品, 新增加了以下功能:
        查看当前的误码率.
        查看误码率告警门
        设置误码率告警门

ODU330.h

#pragma once
#include <string>
#include "ODU.h"

class ODU330 : public ODU {
public:
	ODU330();
	~ODU330();
	float getWarnThreshold();
	bool setWarnThreshold(float threshold);
	float getBER();  //获取当前误码率
	std::string description();

private:
	float  warnThreshold;
};

ODU330.cpp

#include "ODU330.h"
#include "sstream"
ODU330::ODU330() {}
ODU330::~ODU330(){}
float ODU330::getWarnThreshold() {
	return warnThreshold;
}
bool ODU330::setWarnThreshold(float threshold) {
	warnThreshold = threshold;
	return true;
}
float ODU330::getBER() {
	return 0.00005f;  //模拟值
}

std::string ODU330::description() {
	std::stringstream ret;
	ret << "发射功率: " << txPower << "\t发射频率: " << txFreq
		<< "\t带宽: " << bandWidth << "\t误码率: " << getBER()
		<< "\t告警门限: " << warnThreshold;
	return ret.str();
}

main.cpp

#include <iostream>
#include "ODU.h"
#include "ODU330.h"

int main() {
	ODU  odu1;
	odu1.setBandWidth(500);
	odu1.setTxFreq(114000);
	odu1.setTxPower(45);
	std::cout << odu1.description() << std::endl;
	ODU330	 odu2;
	odu2.setBandWidth(600);
	odu2.setTxFreq(119000);
	odu2.setTxPower(48);
	odu2.setWarnThreshold(0.0001);
	std::cout << odu2.description() << std::endl;
	system("pause");
	return 0;
}

项目-持久化存储

用户数据不能永久保存, 程序关闭后, 数据消失.

解决方案: 把数据保存在文件中.

设备:

  1. 文件
  2. 控制台
  3. 特定的数据类型(stringstream)

c++中,必须通过特定的已经定义好的类, 来处理IO(输入输出)

fstream
_EXPORT_STD template <class _Elem, class _Traits>
class basic_fstream : public basic_iostream<_Elem, _Traits> { // input/output stream associated with a C stream
public:
    using _Mybase     = basic_iostream<_Elem, _Traits>;
    using _Myfb       = basic_filebuf<_Elem, _Traits>;
    using _Myios      = basic_ios<_Elem, _Traits>;
    using char_type   = _Elem;
    using traits_type = _Traits;
    using int_type    = typename _Traits::int_type;
    using pos_type    = typename _Traits::pos_type;
    using off_type    = typename _Traits::off_type;
sstream
_EXPORT_STD template <class _Elem, class _Traits, class _Alloc>
class basic_stringstream
    : public basic_iostream<_Elem, _Traits> { // input/output stream associated with a character array
public:
    using _Mybase        = basic_iostream<_Elem, _Traits>;
    using char_type      = _Elem;
iostream
_EXPORT_STD extern "C++" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT istream cin;
_EXPORT_STD extern "C++" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT ostream cout;
_EXPORT_STD extern "C++" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT ostream cerr;
_EXPORT_STD extern "C++" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT ostream clog;
extern "C++" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT istream* _Ptr_cin;
extern "C++" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT ostream* _Ptr_cout;
extern "C++" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT ostream* _Ptr_cerr;
extern "C++" __PURE_APPDOMAIN_GLOBAL _CRTDATA2_IMPORT ostream* _Ptr_clog;
istream
_EXPORT_STD extern "C++" template <class _Elem, class _Traits>
class basic_istream : virtual public basic_ios<_Elem, _Traits> { // control extractions from a stream buffer
public:
    using _Myios = basic_ios<_Elem, _Traits>;
    using _Mysb  = basic_streambuf<_Elem, _Traits>;
    using _Iter  = istreambuf_iterator<_Elem, _Traits>;
    using _Ctype = ctype<_Elem>;
    using _Nget  = num_get<_Elem, _Iter>;
ios
_STD_BEGIN
_EXPORT_STD extern "C++" template <class _Elem, class _Traits>
class basic_ios : public ios_base { // base class for basic_istream/basic_ostream
public:
    using _Myos       = basic_ostream<_Elem, _Traits>;
    using _Mysb       = basic_streambuf<_Elem, _Traits>;
    using _Ctype      = ctype<_Elem>;
    using char_type   = _Elem;
    using traits_type = _Traits;

读写文件:文件流

文件流: 对文件进行读写操作

头文件:  <fstream>

类库:

   ifstream    对文件输入(读文件)

   ofstream    对文件输出(写文件)

   fstream     对文件输入或输出

对文本文件进行读写

模式标志

描述

ios::in

读方式打开文件

ios:out

写方式打开文件

ios::trunc

如果此文件已经存在, 就会打开文件之前把文件长度截断为0

ios::app

尾部最加方式(在尾部写入)

ios::ate

文件打开后, 定位到文件尾

ios::binary

二进制方式(默认是文本方式)

 以上打开方式, 可以使用位操作 |  组合起来

写文本文件

#include <fstream>
#include <iostream>

using namespace std;

int main() {
	string name;
	int age;
	ofstream outfile;
	//也可以使用fstream, 但是fstream的默认打开方式不截断文件长度
	// ofstream的默认打开方式是,  截断式写入 ios::out |  ios::trunc
	// fstream的默认打开方式是,  截断式写入   ios::out
	// 建议指定打开方式
	outfile.open("person.txt", ios::out | ios::trunc);
	while (1) {
		cout << "请输入姓名(输入ctul+z退出程序): ";
		cin >> name;
		if (cin.eof()) break;
		outfile << name << "\t";
		cout << "请输入年龄: ";
		cin >> age;
		if(cin.eof()) break;
		outfile << age << endl;
	}
	outfile.close();
	cout << "数据已保存到文件 person.txt" << endl;
	return 0;
}

上面的年龄如果输入的是非数字,会报错,所以我们需要加一个if(cin.fali()) break;

读文本文件

#include <iostream>
#include <fstream>
using namespace std;
int main() {
	string name;
	int age;
	ifstream fin("person.txt");
	while (1) {
		fin >> name;
		if (fin.eof()) break;
		cout << name << "\t";
		fin >> age;
		cout << age << endl;
	}
	fin.close();
	return 0;
}

二进制文件读写

思考:

文本文件和二进制文件的区别?

文本文件: 写数字1,  实际写入的是 ‘1’

二进制文件:写数字1, 实际写入的是  整数1(4个字节,最低字节是1, 高3个字节都是0)

写字符‘R’实际输入的还是‘R’

二进制文件写

#include <iostream>
#include <fstream>
using namespace std;
int main() {
	string name;
	int age;
	ofstream outfile;
	outfile.open("user.dat" , ios::out | ios::trunc | ios::binary);
	while (1) {
		cout << "Enter name (or 'q' to quit): " << endl;
		cin >> name;
		if (cin.eof()) break;
		outfile << name << "\t";
		cout << "Enter age: " << endl;
		cin >> age;
		if (cin.fail()) break;
		outfile.write((char*)&age, sizeof(age));
		//outfile << age << endl;  //会自动转成文本方式写入
	}
	outfile.close();
	return 0;
}

二进制文件读

#include <iostream>
#include <fstream>
using namespace std;
int main() {
	string name;
	int age;
	ifstream infile;
	infile.open("user.dat" , ios::out | ios::trunc | ios::binary);
	while (1) {
		infile >> name;
		if (infile.eof()) break;
		cout << name << "\t";
		char tmp;
		infile.read(&tmp, sizeof(tmp)); // 跳过中间制表符
		//infile >> age; //从文本文件中读取整数, 使用这个方式
		infile.read((char*)&age, sizeof(age)); // 从二进制文件中读取整数
		cout << age << endl;
	}
	infile.close();
	return 0;
}

对文件流按格式读写取数据

使用stringstream

文件流写数据

#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main() {
	string name;
	int age;
	ofstream fout("person.txt", ios::out | ios::trunc);
	while (1) {
		cout << "Enter name(or eof to quit): ";
		cin >> name;
		if (cin.eof()) break;
		cout << "Enter age: ";
		cin >> age;
		stringstream ss;
		ss << "name=" << name << " age=" << age << endl;
		fout << ss.str();
	}
	fout.close();
	return 0;
}

文件流读数据

没有优雅的C++解决方案, 使用C语言的sscanf

#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main() {
	char name[32];
	int age;
	string line;
	ifstream fin("person.txt");
	while (1) {
		getline(fin, line);
		if (fin.eof()) break;
		sscanf_s(line.c_str(), "name=%s age=%d", name , static_cast<unsigned int>(sizeof(name)), &age);
		cout << "姓名:" << name << " 年龄:" << age << endl;
	}
	fin.close();
	return 0;
}

文件流的状态检查

s.is_open( )文件流是否打开成功,

s.eof( )  流s是否结束

s.fail( ) 流s的failbit或者badbit被置位时, 返回true

failbit: 出现非致命错误,可挽回, 一般是软件错误

badbit置位, 出现致命错误, 一般是硬件错误或系统底层错误, 不可挽回

s.bad( ) 流s的badbit置位时, 返回true

s.good( ) 流s处于有效状态时, 返回true

s.clear( )流s的所有状态都被复位

项目精讲-随机读写:文件流的定位

seekg

seekg( off_type offset     //偏移量    ,    ios::seekdir origin );  //起始位置

作用:设置输入流的位置

参数1: 偏移量

参数2: 相对位置

  beg    相对于开始位置

  cur     相对于当前位置

  end      相对于结束位置

demo

读取当前程序的最后50个字符

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main(void) {
	ifstream infile;
	infile.open("ODU330.cpp");
	if (!infile.is_open()) {
		return 1;
	}
	infile.seekg(-50, infile.end);
	while (!infile.eof()) {
		string line;
		getline(infile, line);
		cout << line << endl;
	}
	infile.close();
	system("pause");
	return 0;
}

tellg

返回该输入流的当前位置(距离文件的起始位置的偏移量)

获取当前文件的长度

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main(void) {
	ifstream infile;
	infile.open("ODU330.cpp");
	if (!infile.is_open()) {
		return 1;
	}
	infile.seekg(0, infile.end);
	int len = infile.tellg();
	cout << len << endl;
	infile.close();
	system("pause");
	return 0;
}

seekp

设置该输出流的位置

demo

先向新文件写入:“123456789”

然后再在第4个字符位置写入“ABC”

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main(void) {
	ofstream out("output.txt");
	if (!out.is_open()) {
		return 1;
	}
	out << "Hello, world!";
	out.seekp(4, out.beg);
	out << "C++";
	out.close();
	return 0;
}

常见错误总结

12节  常见错误总结

  1. 文件没有关闭

文件没有关闭, close(),可能导致写文件失败

  1. 文件打开方式不合适
  2. 在VS2015的部分版本中,当sscanf和sscanf_s的格式字符串中含有中文时,可能会读取失败。在vs2019中未发现该类问题。
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main(void) {
	char name[32];
	int age;
	sscanf_s("汤姆 25", "%s %d", name, 32, &age);
	cout << "Name: " << name << endl;
	cout << "Age: " << age << endl;
	return 0;
}

vs2022也没有问题

项目练习(暂未完成)

文件数据库类Database的设计

需求: 要使用文件来保存用户信息

分析: 设计一个类, 来实现信息的保存功能

Database  数据库

功能:

    init() //初始化, 从文件中读取数据信息, 来初始化用户数据

    autoPair() //自动配对

    print()  // 打印该数据库中的所有用户信息

数据:

    vector<Boy> boys;  //所有的单身男信息

    vector<Girl> girls; //所有单生女信息

项目练习1

为这个项目增加功能:

添加单个用户信息, 并输出该用户的配对结果.

项目练习2

输入任意多个整数, 把这些数据保存到文件data.txt中.

如果在输入的过程中, 输入错误, 则提示用户重新输入.

指导用户输入结束(按ctrl + z)

[每行最多保存10个整数]

cin.ignore(count, c);

从输入流中提取并丢弃字符,直到遇到下列三种情况

1.提取的字符达到了参数count指定的数量

2.在输入序列中遇到文件结束(EOF)

3.输入序列中的下一个字符为参数c指定的字符(这个字符会被提取并丢弃)

项目练习3

从练习2中的num.txt文件读取各个整数, 打印出最大值和最小值, 以及平均值.


http://www.kler.cn/a/368946.html

相关文章:

  • K8s中TSL证书如何续期
  • hudi编译安装,使用spark3的maven指令
  • 量子计算突破:下一个科技革命的风口浪尖在哪里?
  • 多线程进阶——线程池的实现
  • 【PHP】ThinkPHP获取请求的域名及前缀
  • Qt:QtCreator使用
  • 图---java---黑马
  • SELinux详解
  • 图像处理学习笔记-20241021
  • Spring Boot 应用开发全攻略:从入门到精通
  • python——文件存储与写入path
  • CentOS 7 上安装 MySQL 8.0 教程
  • Python入门——yield生成器和iter迭代器
  • 学习记录:js算法(七十六):一手顺子
  • Vue3 跨标签页或跨窗口通信
  • 负载均衡服务器攻击怎么解决最有效?
  • 解决电脑突然没有声音
  • simple_php
  • Flink 源码 TaskManagerRunner 启动 Akka Actor System 源码
  • JVM(HotSpot):GC之G1垃圾回收器
  • FPGA第 13 篇,使用 Xilinx Vivado 创建项目,点亮 LED 灯,Vivado 的基本使用(点亮ZYNQ-7010开发板的LED灯)
  • 深入理解JAVA虚拟机(三)
  • go高并发之路——本地缓存
  • 牛客周赛65(C++实现)
  • 练习LabVIEW第二十二题
  • K8S如何基于Istio重新实现微服务