用硬盘存储文件的形式实现queue的push和pop

用硬盘存储文件的形式实现queue的push和pop

需求

由于本人写的代码垃圾,传感器来的数据高频,算法处理的速度低频,数据又不能舍弃,于是定义了一个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完成之后,文件会变成空文件。
pop结果

小结

很好,又实现了一个没用的功能,这样做频繁的文件操作,效率极其低下,我为什么不每隔一分钟录制一个bag呢,一直读取最老的bag就可以,也不影响一直录制最新的bag啊,简单又高效。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值