rdbuf 在批量数据测试中的应用

本文详细介绍了如何使用C++改变cin输入流和cout输出流,具体包括从文件读取数据并修改cin输入源,以及将输出流更改为文件流进行数据写入。同时,展示了如何恢复默认流状态并从键盘输入数据。

1. 改变cin输入流

#include <iostream>
#include <fstream>

using namespace std;

int main( )
{

	int a,b,c,d;

	// 从main.txt中读取数据
	ifstream infile("c://main.txt");

	// 为恢复cin备份
	streambuf *inrecover = cin.rdbuf();
	
	// 指定cin输入源为流infile,即为main.txt
	cin.rdbuf ( infile.rdbuf() );

	// 程序自动接收数据a,b,c
	cin >> a >> b;
	cin >> c;
	cout << a + b << endl;
	cout << c << endl;
	
	// 恢复cin输入源
	cin.rdbuf ( inrecover );

	// 等待从键盘输入数据
	cin >> d;
	cout << d;

	getchar();
	return 0;
}

2. 改变cout输出流

ofstream outf("out.txt");  
streambuf *strm_buf = cout.rdbuf();  
cout.rdbuf( outf.rdbuf() );  
cout << "write something to file";  
cout.rdbuf(strm_buf); //recover  
cout << "display something on screen";  


#include "pch.h" #include "TCalcFuncSets.h" #include <windows.h> #include <string> #include <vector> #include <fstream> #include <sstream> #include <map> #include <algorithm> #include <iostream> #include <cmath> #include <cctype> #include <unordered_map> #include <mutex> #include <memory> // 用于std::make_shared #include <chrono> // 用于std::chrono时间功能 // 缓存项结构体 struct CacheEntry { std::map<std::string, float> data; std::chrono::steady_clock::time_point lastAccessed; CacheEntry() : lastAccessed(std::chrono::steady_clock::now()) {} }; // 统一的缓存管理类 class QuantileCache { private: std::unordered_map<std::string, CacheEntry> cache_; std::mutex mutex_; const size_t maxCacheSize_ = 100; // 最大缓存项数量 public: // 尝试从缓存获取数据 bool tryGet(const std::string& key, std::map<std::string, float>& result) { std::lock_guard<std::mutex> lock(mutex_); auto it = cache_.find(key); if (it != cache_.end()) { // 更新访问时间 it->second.lastAccessed = std::chrono::steady_clock::now(); result = it->second.data; return true; } return false; } // 存储数据到缓存 void put(const std::string& key, const std::map<std::string, float>& data) { std::lock_guard<std::mutex> lock(mutex_); // 清理过期缓存项 if (cache_.size() >= maxCacheSize_) { evictOldEntries(); } cache_[key].data = data; cache_[key].lastAccessed = std::chrono::steady_clock::now(); } private: // 移除最旧的缓存项 void evictOldEntries() { // 找到最旧的缓存项 auto oldestIt = cache_.begin(); for (auto it = cache_.begin(); it != cache_.end(); ++it) { if (it->second.lastAccessed < oldestIt->second.lastAccessed) { oldestIt = it; } } // 移除最旧的缓存项 cache_.erase(oldestIt); } }; // 全局缓存实例 static QuantileCache g_quantileCache; // 清理字符串中的空白字符 std::string CleanString(const std::string& str) { std::string result; result.reserve(str.size()); for (unsigned int i = 0; i < str.size(); i++) { char c = str[i]; if (!std::isspace((unsigned char)c)) { result.push_back(c); } } return result; } // 清理路径中的无效字符 std::string CleanPath(const std::string& path) { std::string result; result.reserve(path.size()); for (unsigned int i = 0; i < path.size(); i++) { char c = path[i]; if (c == ' ' || !std::isspace((unsigned char)c)) { result.push_back(c); } } return result; } // 将通达信日期格式转换为标准日期格式(yyyymmdd) std::string ConvertTDXDateToYYYYMMDD(float tdxDate) { int dateInt = (int)tdxDate + 19000000; if (dateInt <= 19000000 || dateInt > 21000000) { return ""; } char buffer[16]; sprintf_s(buffer, sizeof(buffer), "%d", dateInt); return std::string(buffer); } // 快速解析日期字符串 std::string ParseDateString(const std::string& dateStr) { // 移除引号 std::string cleaned = dateStr; if (!cleaned.empty() && cleaned[0] == '"') { cleaned = cleaned.substr(1); } if (!cleaned.empty() && cleaned[cleaned.length() - 1] == '"') { cleaned = cleaned.substr(0, cleaned.length() - 1); } // 如果已经是yyyymmdd格式 if (cleaned.length() == 8 && cleaned.find_first_not_of("0123456789") == std::string::npos) { return cleaned; } // 处理分隔符格式 int year = 0, month = 0, day = 0; size_t firstDelim = cleaned.find_first_of("-/\\/"); if (firstDelim != std::string::npos) { size_t secondDelim = cleaned.find_first_of("-/\\/", firstDelim + 1); if (secondDelim != std::string::npos) { year = atoi(cleaned.substr(0, firstDelim).c_str()); month = atoi(cleaned.substr(firstDelim + 1, secondDelim - firstDelim - 1).c_str()); day = atoi(cleaned.substr(secondDelim + 1).c_str()); } } else if (cleaned.length() == 8) { year = atoi(cleaned.substr(0, 4).c_str()); month = atoi(cleaned.substr(4, 2).c_str()); day = atoi(cleaned.substr(6, 2).c_str()); } if (year > 1900 && year < 2100 && month >= 1 && month <= 12 && day >= 1 && day <= 31) { char buffer[16]; sprintf_s(buffer, sizeof(buffer), "%04d%02d%02d", year, month, day); return std::string(buffer); } return ""; } // 处理单个CSV文件并提取指定列的数据 bool ProcessSingleCSVFileForColumn(const std::string& filePath, std::map<std::string, std::vector<double> >& dateColumnMap, int columnIdx) { std::ifstream inFile(filePath.c_str()); if (!inFile.is_open()) { return false; } // 跳过表头 std::string headerLine; if (!std::getline(inFile, headerLine)) { inFile.close(); return false; } std::string line; while (std::getline(inFile, line)) { std::istringstream lineIss(line); std::string token; int columnIndex = 0; std::string dateStr; double columnValue = 0.0; bool hasValue = false; while (std::getline(lineIss, token, ',')) { std::string cleanedToken = CleanString(token); if (columnIndex == 0) { // date列 dateStr = ParseDateString(cleanedToken); } else if (columnIndex == columnIdx) { // 指定列 if (!cleanedToken.empty()) { columnValue = atof(cleanedToken.c_str()); hasValue = true; } } columnIndex++; } // 只有当日期有效且指定列有值时才添加 if (!dateStr.empty() && hasValue) { dateColumnMap[dateStr].push_back(columnValue); } } inFile.close(); return true; } // 处理单个CSV文件并计算N日涨跌幅 bool ProcessSingleCSVFileForReturns(const std::string& filePath, std::map<std::string, std::vector<double> >& dateReturnsMap, int N) { std::ifstream inFile(filePath.c_str()); if (!inFile.is_open()) { return false; } // 跳过表头 std::string headerLine; if (!std::getline(inFile, headerLine)) { inFile.close(); return false; } // 预分配向量空间以提高性能 std::vector<std::string> dates; std::vector<double> closePrices; dates.reserve(1000); // 预估每只股票约1000个交易日 closePrices.reserve(1000); std::string line; while (std::getline(inFile, line)) { std::istringstream lineIss(line); std::string token; int columnIndex = 0; std::string dateStr; double closePrice = 0.0; while (std::getline(lineIss, token, ',')) { std::string cleanedToken = CleanString(token); if (columnIndex == 0) { // date列 dateStr = ParseDateString(cleanedToken); } else if (columnIndex == 5) { // close列 if (!cleanedToken.empty()) { closePrice = atof(cleanedToken.c_str()); } } columnIndex++; } dates.push_back(dateStr); closePrices.push_back(closePrice); } inFile.close(); // 计算N日涨跌幅 for (unsigned int i = N; i < closePrices.size(); i++) { if (!dates[i].empty() && closePrices[i] > 0 && closePrices[i - N] > 0) { double returnRate = (closePrices[i] - closePrices[i - N]) / closePrices[i - N] * 100.0; dateReturnsMap[dates[i]].push_back(returnRate); } } return true; } // 优化的文件处理函数 - 用于计算指定列的分位数 void ReadCSVAndCalculateColumnData(const std::string& directory, std::map<std::string, std::vector<double> >& dateColumnMap, int columnIdx) { WIN32_FIND_DATAA findData; std::string cleanedDirectory = CleanPath(directory); std::string searchPath = cleanedDirectory + "\\*.csv"; HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData); if (hFind == INVALID_HANDLE_VALUE) { return; } do { if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { std::string fileName(findData.cFileName); std::string filePath = cleanedDirectory + "\\" + fileName; filePath = CleanPath(filePath); ProcessSingleCSVFileForColumn(filePath, dateColumnMap, columnIdx); } } while (FindNextFileA(hFind, &findData) != 0); FindClose(hFind); } // 优化的文件处理函数 - 用于计算N日涨跌幅 void ReadCSVAndCalculateReturns(const std::string& directory, std::map<std::string, std::vector<double> >& dateReturnsMap, int N) { WIN32_FIND_DATAA findData; std::string cleanedDirectory = CleanPath(directory); std::string searchPath = cleanedDirectory + "\\*.csv"; HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData); if (hFind == INVALID_HANDLE_VALUE) { return; } do { if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { std::string fileName(findData.cFileName); std::string filePath = cleanedDirectory + "\\" + fileName; filePath = CleanPath(filePath); ProcessSingleCSVFileForReturns(filePath, dateReturnsMap, N); } } while (FindNextFileA(hFind, &findData) != 0); FindClose(hFind); } // 函数前向声明 template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile ); template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile, std::map<std::string, std::vector<double>>& dateDataMap ); float CalculateQuantile(const std::vector<double>& data, float quantile); // 通用分位数数据处理函数 // 提取两个主要函数的公共数据处理逻辑 template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile ) { // 存储日期对应的数据 std::map<std::string, std::vector<double>> dateDataMap; // 调用传入的函数读取数据 readDataFunc(csvDirectory, dateDataMap); // 计算每个日期的分位数 for (const auto& entry : dateDataMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, quantile); } // 清理数据以释放内存 dateDataMap.clear(); } // 兼容不同参数类型的重载版本 template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile, std::map<std::string, std::vector<double>>& dateDataMap ) { // 调用传入的函数读取数据 readDataFunc(csvDirectory, dateDataMap); // 计算每个日期的分位数 for (const auto& entry : dateDataMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, quantile); } } // 计算分位数 - 使用O(n)时间复杂度的优化算法 float CalculateQuantile(const std::vector<double>& data, float quantile) { if (data.empty()) { return 0.0f; } if (quantile < 0.0f) quantile = 0.0f; if (quantile > 1.0f) quantile = 1.0f; std::vector<double> sortedData = data; size_t n = sortedData.size(); double pos = quantile * (n - 1); int lowerIndex = static_cast<int>(pos); int upperIndex = lowerIndex + 1; // 对于精确索引的情况,直接使用nth_element if (lowerIndex == upperIndex || upperIndex >= static_cast<int>(n)) { std::nth_element(sortedData.begin(), sortedData.begin() + lowerIndex, sortedData.end()); return static_cast<float>(sortedData[lowerIndex]); } // 对于需要插值的情况,找到两个位置的元素 // 先找lowerIndex位置的元素 std::nth_element(sortedData.begin(), sortedData.begin() + lowerIndex, sortedData.end()); double lowerValue = sortedData[lowerIndex]; // 再在lowerIndex之后的范围内找upperIndex位置的元素 std::nth_element(sortedData.begin() + lowerIndex + 1, sortedData.begin() + upperIndex, sortedData.end()); double upperValue = sortedData[upperIndex]; // 线性插值计算最终分位数值 double fractionalPart = pos - lowerIndex; double quantileValue = lowerValue + fractionalPart * (upperValue - lowerValue); return static_cast<float>(quantileValue); } // 生成缓存键值 std::string GenerateColumnCacheKey(int columnIdx, float quantile) { char buffer[64]; sprintf_s(buffer, "column_%d_%.2f", columnIdx, quantile); return std::string(buffer); } std::string GenerateReturnsCacheKey(int N, float quantile) { char buffer[64]; sprintf_s(buffer, "returns_%d_%.2f", N, quantile); return std::string(buffer); } // 函数2 - 计算指定列的分位数 void CalculateColumnQuantileReturns(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc) { // 初始化输出数组为0 for (int i = 0; i < DataLen; i++) { pfOUT[i] = 0.0f; } // 获取列索引和分位数参数 int columnIdx = (int)(pfINb[0] + 0.5f); // M参数表示列号 float quantile = pfINc[0]; // N参数表示分位数 // 生成缓存键值,添加前缀以区分不同类型的缓存 std::string cacheKey = "column:" + GenerateColumnCacheKey(columnIdx, quantile); // 检查缓存中是否已有计算结果 std::map<std::string, float> dateQuantileMap; bool hasCache = g_quantileCache.tryGet(cacheKey, dateQuantileMap); // 如果缓存中没有,则进行计算 if (!hasCache) { // 设置CSV文件的目录 const std::string csvDirectory = "F:\\His_STOCKDATA"; // 使用堆分配存储日期对应的指定列数据,避免栈溢出 auto dateColumnMap = std::make_shared<std::map<std::string, std::vector<double>>>(); // 读取CSV文件并提取指定列的数据 ReadCSVAndCalculateColumnData(csvDirectory, *dateColumnMap, columnIdx); // 计算每个日期的分位数 for (const auto& entry : *dateColumnMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, quantile); } // 自动释放内存(通过shared_ptr的作用域) // 将结果存入缓存 g_quantileCache.put(cacheKey, dateQuantileMap); } // 将结果匹配到输出数组 for (int i = 0; i < DataLen; i++) { std::string dateStr = ConvertTDXDateToYYYYMMDD(pfINa[i]); if (dateStr.empty() || dateStr.length() != 8) { pfOUT[i] = 0.0f; continue; } std::map<std::string, float>::const_iterator iter = dateQuantileMap.find(dateStr); if (iter != dateQuantileMap.end()) { pfOUT[i] = iter->second; } else { pfOUT[i] = 0.0f; } } } // 函数3 - 快速计算分位数收益 void CalculateQuantileReturns(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc) { // 初始化输出数组为0 for (int i = 0; i < DataLen; i++) { pfOUT[i] = 0.0f; } // 获取N和M的值 int N = (int)(pfINb[0] + 0.5f); float M = pfINc[0]; // 生成缓存键值,添加前缀以区分不同类型的缓存 std::string cacheKey = "returns:" + GenerateReturnsCacheKey(N, M); // 检查缓存中是否已有计算结果 std::map<std::string, float> dateQuantileMap; bool hasCache = g_quantileCache.tryGet(cacheKey, dateQuantileMap); // 如果缓存中没有,则进行计算 if (!hasCache) { // 设置CSV文件的目录 const std::string csvDirectory = "F:\\His_STOCKDATA"; // 使用堆分配存储日期对应的涨跌幅数据,避免栈溢出 auto dateReturnsMap = std::make_shared<std::map<std::string, std::vector<double>>>(); // 读取CSV文件并计算N日涨跌幅 ReadCSVAndCalculateReturns(csvDirectory, *dateReturnsMap, N); // 计算每个日期的分位数 for (const auto& entry : *dateReturnsMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, M); } // 自动释放内存(通过shared_ptr的作用域) // 将结果存入缓存 g_quantileCache.put(cacheKey, dateQuantileMap); } // 将结果匹配到输出数组 for (int i = 0; i < DataLen; i++) { std::string dateStr = ConvertTDXDateToYYYYMMDD(pfINa[i]); if (dateStr.empty() || dateStr.length() != 8) { pfOUT[i] = 0.0f; continue; } std::map<std::string, float>::const_iterator iter = dateQuantileMap.find(dateStr); if (iter != dateQuantileMap.end()) { pfOUT[i] = iter->second; } else { pfOUT[i] = 0.0f; } } } // 函数注册 PluginTCalcFuncInfo g_CalcFuncSets[] = { {2, (pPluginFUNC)CalculateColumnQuantileReturns}, {3, (pPluginFUNC)CalculateQuantileReturns}, {0, NULL}, }; BOOL RegisterTdxFunc(PluginTCalcFuncInfo** pFun) { if (*pFun == NULL) { (*pFun) = g_CalcFuncSets; return TRUE; } return FALSE; }有哪些可以深度优化的地方
09-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值