C++读写编辑CSV文件示例源码 用于数据导入导出,比Excel好使

我用到的场景:密钥注入

使用说明:

1、从STORM导出SN和公钥,放在SN.csv里,把SN.csv和插件全放在个性化目录下

2、运行插件会自动生成index+SN.txt文件,内容为sn+","+ ikeyespk+","+kcv+","+ksn+","+group_name+","+to_string(index);

3、index+SN.csv文件需要处理下格式,再导入STORM系统,再由STORM注入IPEK。(index为16进制)

不用设备和其它工位。全部SN对应的IPEK生成完成后,SN.csv里对应的SN行的状态会改为PASS,如果需要重新生成,删除这一列,重新运行插件即可。

源码

cpp 复制代码
// SCPMReader.cpp : Defines the initialization routines for the DLL.
//
#include <stdlib.h>
#include "pch.h"

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

//#include "httpclient/json.h" //#include 是以当前文件所在路径为当前目录
//#ifdef _AFXDLL
//#pragma comment(lib,"httpclient/jsoncpp_static.lib") //#pragma comment 是以当前工程所在路径为当前目录
//#else
//#pragma comment(lib,"httpclient/jsoncpp_static_MT.lib") //#pragma comment 是以当前工程所在路径为当前目录
//#endif


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static bool isSuccess = false;
static string sn = "";
static string session_public_key_hex = "";
static string ikeyespk = "";
static string kcv = "";
static string ksn = "";
static string group_name = "";
static string other = "";//其它自定义参数
struct DeviceInfo {
	std::string sn;
	std::string session_public_key;

	std::string group_name;
	std::string index;
	std::string ikeyespk;
	std::string kcv;
	std::string ksn;

};

std::vector<DeviceInfo> loadDeviceData(const std::string& filename) {
	std::vector<DeviceInfo> devices;
	std::ifstream file(filename);
	std::string line;

	if (!file.is_open()) {
		std::cerr << "无法打开文件: " << filename << std::endl;
		return devices;
	}

	while (std::getline(file, line)) {
		std::stringstream ss(line);
		std::string item;
		std::vector<std::string> tokens;

		while (std::getline(ss, item, ',')) {
			tokens.push_back(item);
		}

		if (tokens.size() == 2) {
			DeviceInfo device = { tokens[0], tokens[1] };
			devices.push_back(device);
		}
		else {
			std::cerr << "格式错误: " << line << std::endl;
		}
	}

	file.close();
	return devices;
}
bool StartsWith(const string& str, const string& prefix)
{
	if (str.size() < prefix.size())
	{
		return false;
	}

	return str.compare(0, prefix.size(), prefix) == 0;
}

#include <iomanip>
bool halInjectKey(int index=0)
{
	char SnFileName[5000] = { 0 };
	GetPrivateProfileString("CFG_FILE", "SnFileName", "SN.csv", SnFileName, 5000, CONFIG_FILE_NAME);

	//index 转16进制字符串 4位 不足补0 大写
	std::stringstream ss;
	ss << std::uppercase          // 大写 HEX
		<< std::hex
		<< std::setw(2)            // 宽度
		<< std::setfill('0')       // 不足补0
		<< index;

	std::string hexIndex = ss.str();

	{



		std::string filePath2 = hexIndex + SnFileName;
		logger.INFO_F("halInjectKey filePath2=" + filePath2 + P(index));

		// 追加模式打开
		ofstream fout(filePath2, ios::app);

		if (!fout.is_open())
		{
			logger.ERROR_F("打开文件失败");
			return -1;
		}

		// 追加一行
		string line = sn + "," + ikeyespk + "," + kcv + "," + ksn + "," + group_name + "," + hexIndex;
		fout << line << endl;
		logger.INFO_F("追加一行为:" + line);
		fout.close();
	}
	
	{
		std::string filePath = SnFileName;
		// 读取所有行 并找到当前SN所在行
		vector<string> lines;

		ifstream fin(filePath);

		string line;
		int i = 0;
		while (getline(fin, line))
		{
			lines.push_back(line);

			if (StartsWith(line, sn))
			{
	
				logger.INFO_F("SN匹配成功,行(从0开始):" + P(i)); 

				lines[i] = "PASS," + lines[i];
				logger.INFO_F("替换指定行内容为:" + lines[i]);
			}
			else {
				i++;
			}
		}

		fin.close();

		

		// ======================
		// 写回文件
		// ======================

		ofstream fout(filePath);

		for (const auto& l : lines)
		{
			fout << l << endl;
		}

		fout.close();

		cout << "替换完成" << endl;
	}




	
	return true;


	//char buffer[2000] = { 0 }; // 足够大的缓冲区来存储返回的数据
	//GetPrivateProfileString("PLUGIN", "other", ",\"type\":1,\"algorithm\":4", buffer, sizeof(buffer), CONFIG_FILE_NAME);
	//other = string(buffer);

	//char recvBuff[5000] = { 0 };
	//int recvLen = sizeof(recvBuff);
	//string json="{\"function\":\"key_injection\",\"index\":"+to_string(index) + ",\"group_name\":\"" + group_name + "\",\"ikeyespk\":\"" + ikeyespk + "\",\"kcv\":\"" + kcv + "\",\"ksn\":\"" + ksn + "\""+other+"}";
	//if (ERR_SUCCESS == mySocket.SendAndRecv(json.c_str(), json.length(), recvBuff, &recvLen, 5000))
	//{
	//	Json::Reader reader;
	//	Json::Value value;
	//	if (reader.parse(recvBuff, value))
	//	{
	//		string message = value["message"].asString();
	//		if (!message._Equal("success")) { return false; }
	//		return true;
	//	}
	//	else { logger.ERROR_F(FUN_LINE" response json parse error!"); }
	//}
	//return false;
}


//hCard 没意义
//pCmd {class,ins,p1,?,lc,dataStart}
// P1=1 TUSN 只是赋值
// P1=2 KEY 只是赋值
// P1=3 KCV 赋值 并写入TUSN和KEY 返回 成功 2个字节[0x90,00]  失败其它
// P1=0x20 读TUSN  返回 8个字节0+TUSN+2个字节[0x90,00]
//if success return 0
int SendAPDU2(HANDLE hCard,	const char *pCmd, 	int nCmdLen,	char *pRsp,	int& nRspLen,	const char* pPath)
{
	logger.INFO_F("Enter SendAPDU2");
	logger.INFO_F("CMD:"+bytesToHexString((const BYTE*)pCmd, nCmdLen)+"  "+P(nRspLen));
	nRspLen = 0;
	unsigned char swOK[] = { 0x90,0x00 };//正常返回
	BYTE isoClass = pCmd[0];
	BYTE isoRW = pCmd[1];
	BYTE isoP1 = pCmd[2];
	BYTE isoP2 = pCmd[3];

	if (0x80 == isoClass)
	{
		if (0xB0 == isoRW) //Read
		{
			if (0x04 == isoP1)//读POS公钥
			{
				nRspLen += session_public_key_hex.size();  // pRsp  最大只能存2个字节 我把读的sn放回参数pRsp里  ,执行脚本成功后,点确定 脚本工具会崩溃重启 ,这是脚本工具的问题吧?
				memcpy(pRsp, session_public_key_hex.c_str(), session_public_key_hex.size());
				logger.INFO_F("读POS公钥:success");
			}
			else if (0x05 == isoP1)//读SN
			{
				nRspLen += sn.size();
				memcpy(pRsp, sn.c_str(), sn.size());
				logger.INFO_F("读SN:success");
			}
			else
			{
				logger.ERROR_F("P1 Error");
				return -3;
			}
		}
		else if (0xD0 == isoRW) //Write
		{
			int isoDataLength = pCmd[4];
			const char* pDataStart = pCmd + 5;
			if (nCmdLen > (255 + 5)) //数据超过255 用2字节表示长度 高字节在前  密钥256字节
			{
				isoDataLength = pCmd[5]*256+ pCmd[6];
				pDataStart = pCmd + 7;
			}

			if (0x06 == isoP1)//写设备密文密钥
			{
				ikeyespk = bytesToHexString((const BYTE*)pDataStart, isoDataLength);
				logger.INFO_F(to_string(isoP2 ) + "组 写设备密文密钥IPEK:success :"+ ikeyespk);
			}
			else if (0x07 == isoP1)//写密钥校验值KCV
			{
				kcv = bytesToHexString((const BYTE*)pDataStart, isoDataLength);
				logger.INFO_F(to_string(isoP2 )+"组 KCV:success :"+kcv);

				if (!halInjectKey(isoP2)) { return -9; }
				logger.INFO_F(to_string(isoP2) + "组注入密钥:success");
			}
			else if (0x08 == isoP1)//写KSN
			{
				ksn = bytesToHexString((const BYTE*)pDataStart, isoDataLength);
				logger.INFO_F(to_string(isoP2 ) + "组 KSN:success :" + ksn);
			}
			else if (0x09 == isoP1)//写组名
			{
				group_name = string(pDataStart);// hexStringToString(pDataStart);//字符串 //bytesToHexString((const BYTE*)pDataStart, isoDataLength);
				logger.INFO_F(to_string(isoP2) + "组 group_name:success :" + group_name); 
			}
			else
			{
				logger.ERROR_F("P1 Error2");
				return -3;
			}

		}
		else
		{
			logger.ERROR_F("RW Error");
			return -2;
		}
	}
	else
	{
		logger.ERROR_F("Class Error");
		return -1;
	}

	
	memcpy(pRsp+nRspLen,swOK,2);
	nRspLen += 2;
	logger.INFO_F("SendAPDU2 Success");
	return 0;
}
int WINAPI SendAPDU(HANDLE hCard,	const char* pCmd,	int nCmdLen,	char* pRsp,	int& nRspLen,	const char* pPath)
{
	RunCmd(__FUNCTION__);
	int ret = -100;
	for (int i = 0; i < 5; i++)
	{
		ret = SendAPDU2(hCard, pCmd, nCmdLen, pRsp, nRspLen, pPath);
		if (ret == 0) { isSuccess = true;  return ret; }
		Sleep(100);
	}
	isSuccess = false;
	return ret;
}


//if success return 0 else non 0. 
int WINAPI OpenReader(HANDLE& hCT, const char* ucpCardCT, const int iPersoNo, const char* pPath)
{
	logger.INFO_F("Enter OpenReader " + string(ucpCardCT));
	RunCmd(__FUNCTION__);
	logger.INFO_F("连接:成功 (不连设备)");
	//读取sn和公钥session_public_key_hex
	char SnFileName[5000] = {0};
	GetPrivateProfileString("CFG_FILE", "SnFileName", "SN.csv", SnFileName, 5000, CONFIG_FILE_NAME);
	std::string filename = SnFileName; 
	std::vector<DeviceInfo> devices = loadDeviceData(filename);

	if (devices.size() == 0) { logger.ERROR_F(FUN_LINE"未找到有效的sn和公钥session_public_key_hex!请检查文件是否存在或是否全部已经完成。 SnFileName="+string(SnFileName)); return -2; }
	for (const auto& device : devices) {
		sn = device.sn;
		
		if (sn.length() > 0 && device.session_public_key.length() > 0)
		{
			std::vector<unsigned char> decoded = base64_decode(device.session_public_key);
			std::string decoded_str(decoded.begin(), decoded.end());
			session_public_key_hex = decoded_str;
			//logger.INFO_F(PS(session_public_key_hex));
			logger.INFO_F(P(session_public_key_hex.size()));
			logger.INFO_F("session_public_key_hex=" + encodeHexString(session_public_key_hex));
			logger.INFO_F(FUN_LINE + "load sn success, " + PS(sn));
			return 0;
		}
		else
		{
			logger.ERROR_F(FUN_LINE" sn length or session_public_key length error!");
			return -1;
		}
	}
	return 0;
}
//成功 返回 0
int WINAPI CloseReader(HANDLE hCT, const char* pPath)
{	
	logger.INFO_F("Enter CloseReader");
	RunCmd(__FUNCTION__ "Final");
	return 0;
}
int WINAPI EjectICC(HANDLE hCard,
	const char* pStatus,
	int nStatusLen,
	const char* pPath)
{
	logger.INFO_F("Enter EjectICC");
	return 0;
}
int WINAPI GetUID(HANDLE hCard, unsigned char *pucUID, int &nUIDLen)
{
	logger.INFO_F("Enter GetUID");
	return 0;
}
int WINAPI CardReset(HANDLE hCard, unsigned char* pucATR, int& nATRLen, const char* pPath)
{
	logger.INFO_F("Enter CardReset");
	return 0;
}
int WINAPI RequestICC(HANDLE hCard,
	char* pData,
	int& nDataLen,
	const char* pPath)
{
	logger.INFO_F("Enter RequestICC");
	return 0;

}
相关推荐
郭涤生1 小时前
C++各个版本的性能和安全性总结
开发语言·c++
wljy13 小时前
二、静态库的制作和使用
linux·c语言·开发语言·c++
道剑剑非道3 小时前
FFmpeg 6.0 实战:用 C++ 封装摄像头采集与 RTSP 推流
开发语言·c++·ffmpeg
天天进步20153 小时前
Python全栈项目实战:基于深度学习的语音合成(TTS)系统
开发语言·python·深度学习
OctShop大型商城源码3 小时前
.NET线上商城源码_C#商城源码_技术赋能下的电商新生态
开发语言·c#·.net·商城系统源码
光电笑映3 小时前
从环境变量到进程虚拟地址空间——Linux 内存管理的底层脉络
linux·服务器·c++·c
IT猿手3 小时前
光伏模型参数估计:基于山羊优化算法(GOA )的光伏模型参数辨识问题求解研究,免费提供完整MATLAB代码链接
开发语言·算法·matlab·群智能优化算法·智能优化算法·光伏模型参数估计·光伏模型参数辨识
xrgs_shz4 小时前
【高光谱数据处理实战】基于Python的ENVI图像交互式裁剪与光谱数据预处理
开发语言·图像处理·python
MATLAB代码顾问4 小时前
麻雀搜索算法(SSA)原理详解与Python实现
开发语言·python