需求
由于本人写的代码垃圾,传感器来的数据高频,算法处理的速度低频,数据又不能舍弃,于是定义了一个queue用来一边push新的数据,一边pop并处理旧的数据,但是随着时间推移,内存爆了,于是想硬盘空间大,能不能用硬盘实现这个功能。
代码
创建一个头文件DataCache.h,里面写了一个模板类用于实现push 和pop
#pragma once
#include <iostream>
#include <fstream>
#include <mutex>
#include <unistd.h>
#include <cstdio>
template<typename T>
class DataCache
{
public:
DataCache() : size_(0)
{
if (remove(FILE_NAME) == 0)
{
std::cout << "Removed previous " << FILE_NAME << std::endl;
}
}
void push(const T& data)
{
std::unique_lock<std::mutex> lock(mutex_);
writeToFile(data);
++size_;
}
bool pop(T& data)
{
std::unique_lock<std::mutex> lock(mutex_);
bool success = false;
if (size_ > 0)
{
// data = readFromFile(0);
data = readFromFile();
--size_;
// removeFromFile(0); // 从文件中删除弹出的数据
removeFromFile(); // 从文件中删除弹出的数据
success = true;
}
return success;
}
size_t size() const
{
std::unique_lock<std::mutex> lock(mutex_);
return size_;
}
private:
void writeToFile(const T& data)
{
std::ofstream outfile;
outfile.open(FILE_NAME, std::ios::binary | std::ios::app);
outfile.write(reinterpret_cast<const char *>(&data), sizeof(data));
outfile.close();
}
T readFromFile() const
{
std::ifstream infile;
infile.open(FILE_NAME, std::ios::binary);
T data;
infile.read(reinterpret_cast<char *>(&data), sizeof(T));
infile.close();
return data;
}
void removeFromFile()
{
// 打开文件并获取文件的大小
std::fstream file(FILE_NAME, std::ios::in | std::ios::out | std::ios::binary);
file.seekg(0, std::ios::end);
size_t file_size = file.tellg();
file.seekg(0, std::ios::beg);
// 计算要删除的元素的字节数和位置
size_t element_size = sizeof(T);
// 从文件中删除第一个数据
if (element_size <= file_size)
{
if (element_size < file_size)
{
char buffer[file_size - element_size];
file.seekg(element_size, std::ios::beg);
file.read(buffer, file_size - element_size);
file.seekp(0, std::ios::beg);
file.write(buffer, file_size - element_size);
}
// 截断文件,删除最后一个元素
file_size -= element_size;
if (truncate(FILE_NAME, file_size) != 0)
{
std::cerr << "Error: truncate() failed" << std::endl;
return;
}
}
file.close();
}
size_t size_;
mutable std::mutex mutex_;
const char *FILE_NAME = "data.dat";
};
创建一个file_buf.cpp文件用于测试,测试代码开了两个线程,一个线程用于高频push,一个线程用来低频pop,通过打印发现代码运行正常。
#include <iostream>
#include <thread>
#include "DataCache.h"
void pushData(DataCache<int>& cache)
{
for (int i = 0; i < 1e10; ++i)
{
cache.push(i);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 等待一段时间以确保 push 更快
}
std::cerr <<"finshed push" << std::endl;
}
void popData(DataCache<int>& cache)
{
int old_data =0 , data= 0;
while (1)
{
if(cache.pop(data))
{
std::cout << data << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 等待一段时间以模拟处理 pop 的时间
}
}
int main()
{
DataCache<int> cache;
std::thread pushThread(pushData, std::ref(cache));
std::thread popThread(popData, std::ref(cache));
pushThread.join();
popThread.join();
std::cout << "Final cache size: " << cache.size() << std::endl;
return 0;
}
在ubuntu18 c++11 中使用如下命令进行编译
g++ file_buff.cpp -std=c++11 -pthread -o filebuf
生成一个filebuf文件,执行命令:
./filebuf
会正常打印出文件中的头文件,当pop完成之后,文件会变成空文件。
小结
很好,又实现了一个没用的功能,这样做频繁的文件操作,效率极其低下,我为什么不每隔一分钟录制一个bag呢,一直读取最老的bag就可以,也不影响一直录制最新的bag啊,简单又高效。