本例子利用线程进行缓冲存储
QFileSaveThead.h
/*************************************************************************
接口描述:文件存储类
拟制:
接口版本:V1.0
时间:20220922
说明:利用线程和缓存进行文件存储
*************************************************************************/
#ifndef QFILESAVETHREAD_H
#define QFILESAVETHREAD_H
#include <QFile>
#include <QMutex>
#include <QQueue>
#include <QThread>
#include <qsemaphore.h>
class QFileSaveThread : public QThread
{
Q_OBJECT
public:
explicit QFileSaveThread(short nCacheMax = 100, QObject *parent = nullptr);
~QFileSaveThread();
protected:
volatile bool m_bStop;
QMutex m_mutex;
QMutex m_mutexQueue;
QSemaphore m_freeSpace;
QSemaphore m_usedSpace;
QQueue<TDataBuffer> m_queueDataBuffer;
QFile m_file; //存储文件
unsigned int m_nCacheSize; //缓存大小默认1MB
unsigned short m_nCacheMax;//最大缓冲块数目
byte *m_pBuffer; //缓存数据
unsigned int m_nWritePos; //写入位置
bool m_bOpen;
QString m_qsFilePath;
int m_nFaileAllocateCount;//分配内存失败次数
long long m_llWriteSize;//写入字节数
private:
void ClearBuf(void); //清除Buffer
public:
bool CreatFile(QString qsFilePath); //打开文件
unsigned int GetCacheSize() const;//获得缓冲块大小
void SetCacheSize(int nCacheSize);//设置缓冲块大小
unsigned int GetCacheMax() const;//获得最大缓冲块数目
long long WriteFile(byte *pBuffer, int nLen); //写文件
void CloseFile(); //关闭写文件
long long GetWriteSize();//获得写入字节数
// QThread interface
protected:
virtual void run() override;
};
#endif // QFILESAVETHREAD_H
QFileSaveThead.cpp
#include "qfilesavethread.h"
#include <QDebug>
#include <QDir>
QFileSaveThread::QFileSaveThread(short nCacheMax, QObject *parent)
: QThread(parent)
, m_freeSpace(nCacheMax)
, m_nCacheMax(nCacheMax)
{
m_bStop = false;
m_nCacheSize = 1 * 1024 * 1024; //1MB
m_pBuffer = nullptr;
m_nWritePos = 0;
m_nFaileAllocateCount = 0;
m_bOpen = false;
m_llWriteSize = 0;
start(QThread::TimeCriticalPriority);
}
QFileSaveThread::~QFileSaveThread()
{
m_mutexQueue.lock(); //进入临界区
m_bStop = true;
m_usedSpace.release();
this->wait();
m_mutexQueue.unlock(); //离开临界区
CloseFile();
ClearBuf();
}
unsigned int QFileSaveThread::GetCacheSize() const
{
return m_nCacheSize;
}
void QFileSaveThread::SetCacheSize(int nCacheSize)
{
QMutexLocker locker(&m_mutex);
m_nCacheSize = nCacheSize;
}
unsigned int QFileSaveThread::GetCacheMax() const
{
return m_nCacheMax;
}
long long QFileSaveThread::WriteFile(byte *pBuffer, int nLen)
{
if(m_nFaileAllocateCount >= 10)
return m_llWriteSize;
QMutexLocker locker(&m_mutex);
if (!m_file.isOpen())
return m_llWriteSize;
if (m_pBuffer == nullptr) {
m_pBuffer = new (std::nothrow) byte[m_nCacheSize];
if(m_pBuffer == nullptr)
{
qDebug() << "Failed to allocate memory.";
m_nFaileAllocateCount++;
}
m_nWritePos = 0;
}
if (m_pBuffer!= nullptr)
{
if(m_nWritePos + nLen < m_nCacheSize) {
memcpy(m_pBuffer + m_nWritePos, pBuffer, nLen);
m_llWriteSize += nLen;
m_nWritePos += nLen;
} else //写入数据
{
bool bCopy = false;
if (m_nWritePos + nLen == m_nCacheSize) {
memcpy(m_pBuffer + m_nWritePos, pBuffer, nLen);
m_llWriteSize += nLen;
m_nWritePos += nLen;
bCopy = true;
}
TDataBuffer tDataBuffer;
tDataBuffer.pBuffer = m_pBuffer;
tDataBuffer.nLen = m_nWritePos;
if (m_freeSpace.tryAcquire()) {
m_mutexQueue.lock(); //进入临界区
m_queueDataBuffer.append(tDataBuffer);
//qDebug() << m_queueDataBuffer.size();
m_mutexQueue.unlock(); //离开临界区
m_usedSpace.release(); //消费锁释放
} else {
qDebug()
<< "----------The storage file queue is too long to be reproduced!----------\r";
}
m_pBuffer = new (std::nothrow) byte[m_nCacheSize];
if(m_pBuffer == nullptr)
{
qDebug() << "Failed to allocate memory.";
m_nFaileAllocateCount++;
}
//缓存不够拷贝,将本包拷贝至下一次缓冲区
if (m_pBuffer!= nullptr && !bCopy) {
memcpy(m_pBuffer, pBuffer, nLen);
m_llWriteSize += nLen;
m_nWritePos = nLen;
} else
m_nWritePos = 0;
}
}
return m_llWriteSize;
}
void QFileSaveThread::CloseFile()
{
m_bOpen = false;
m_mutexQueue.lock(); //进入临界区
while (!m_queueDataBuffer.empty()) {
TDataBuffer tDataBuffer = m_queueDataBuffer.dequeue();
if (tDataBuffer.pBuffer != nullptr) {
if (m_file.isOpen())
{
m_file.write((char *) tDataBuffer.pBuffer, tDataBuffer.nLen);
}
delete[] tDataBuffer.pBuffer;
}
}
m_mutexQueue.unlock(); //离开临界区
QMutexLocker locker(&m_mutex);
if (m_pBuffer != nullptr) {
if (m_file.isOpen())
m_file.write((char *) m_pBuffer, m_nWritePos);
delete[] m_pBuffer;
m_pBuffer = nullptr;
m_nWritePos = 0;
}
if (m_file.isOpen()) {
if (m_file.size() == 0)
m_file.remove();
m_file.close();
}
}
long long QFileSaveThread::GetWriteSize()
{
return m_llWriteSize;
}
void QFileSaveThread::ClearBuf()
{
QMutexLocker locker(&m_mutex);
while (!m_queueDataBuffer.empty()) {
TDataBuffer tDataBuffer = m_queueDataBuffer.dequeue();
if (tDataBuffer.pBuffer != nullptr)
delete[] tDataBuffer.pBuffer;
}
if (m_pBuffer != nullptr)
delete[] m_pBuffer;
}
bool QFileSaveThread::CreatFile(QString qsFilePath)
{
m_qsFilePath = qsFilePath;
QMutexLocker locker(&m_mutex);
if (m_file.isOpen())
m_file.close();
m_file.setFileName(qsFilePath);
QString qsDir = qsFilePath.left(qsFilePath.lastIndexOf("/"));
if(qsDir == qsFilePath)
{
qsDir = qsFilePath.left(qsFilePath.lastIndexOf("\\"));
}
QDir qDir;
qDir.mkpath(qsDir);
m_bOpen = m_file.open(QIODevice::Append | QIODevice::ReadWrite);
qDebug() << "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
qDebug() << "Creat save file" << qsFilePath;
qDebug() << "Cache size is" << m_nCacheSize << "byte";
qDebug() << "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
m_llWriteSize = 0;
return m_bOpen;
}
void QFileSaveThread::run()
{
while (!m_bStop) {
m_usedSpace.acquire();
if (m_bStop)
return;
while (!m_bStop && !m_queueDataBuffer.empty()) {
m_mutexQueue.lock(); //进入临界区
TDataBuffer tDataBuffer = m_queueDataBuffer.dequeue();
//qDebug() << m_queueDataBuffer.size();
m_mutexQueue.unlock(); //离开临界区
m_freeSpace.release();
//处理数据
if (tDataBuffer.pBuffer != nullptr) {
if (m_file.isOpen())
{
m_file.write((char *) tDataBuffer.pBuffer, tDataBuffer.nLen);
}
delete[] tDataBuffer.pBuffer;
}
}
}
}