原理: 保存文件头,再截取数据, 最后将两者进行拼接
#pragma pack(push,1)
// WAV格式
struct WaveHeader
{
// RIFF 头;
char riff_fileid[4]; // "RIFF" 大端 "RIFF"块(0x52494646),标记为RIFF文件格式
quint32 riff_fileLen; // 块数据域大小(Chunk Size),即从下一个地址开始,到文件末尾的总字节数,或者文件总字节数-8
// 数据类型标识符;
char waveid[4]; // "WAVE" 类型码(Form Type),WAV文件格式标记,即"WAVE"四个字母
// 格式块中的块头;
char fmt_chkid[4]; //"fmt" 子块(0x666D7420),注意末尾的空格
quint32 fmt_chkLen; // 子块数据域大小
// 格式块中的块数据;
quint16 wFormatTag; /* format type */ // 编码格式(Audio Format),1代表PCM无损格式
quint16 nChannels; /* number of channels (i.e. mono, stereo, etc.) */ // 声道数(Channels),1或2
quint32 nSamplesPerSec; /* sample rate */ // 传输速率(Byte Rate),每秒数据字节数,SampleRate * Channels * BitsPerSample / 8
quint32 nAvgBytesPerSec; /* for buffer estimation */ // 每秒数据大小 每个采样所需的字节数BlockAlign,BitsPerSample*Channels/8
quint16 nBlockAlign; /* block size of data */ // 单个采样位深(Bits Per Sample),可选8、16或32
quint16 wBitsPerSample; // "data"子块 (0x64617461)
char data_chkid[4]; //"DATA" // 子块数据域大小(SubChunk Size) 至此,共44字节大小
quint32 data_chkLen; // PCM音频数据
WaveHeader()
{
initHeader();
}
// 初始化WAV格式
void initHeader(quint16 nChannelCnt = 2, quint32 nSampleRate = 44100, quint16 nBitsPerSample = 16)
{
strcpy(riff_fileid, "RIFF");
riff_fileLen = 36;
strcpy(waveid, "WAVE");
strcpy(fmt_chkid, "fmt ");
fmt_chkLen = 16;
wFormatTag = 1;
nChannels = nChannelCnt;
nSamplesPerSec = nSampleRate;
wBitsPerSample = nBitsPerSample;
nBlockAlign = nChannels * wBitsPerSample / 8; // 每秒数据大小(字节) = 采样率 * 声道数 * sample比特数 / 8
nAvgBytesPerSec = nBlockAlign * nSamplesPerSec;
strcpy(data_chkid, "data");
data_chkLen = 0;
}
void setDataSize(int len)
{
riff_fileLen += len;
data_chkLen += len;
}
};
#define WaveHeaderLength sizeof(WaveHeader)
#pragma pack(pop)
#include <QCoreApplication>
#include <QFile>
#include <QDebug>
#include <fstream>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const qint64 SIZE = 1024 * 800;
QString filename = "E:\\test.wav";
QFile file(filename);
file.open(QIODevice::ReadOnly);
QFile fileSave("E:\\save_test.wav");
fileSave.open(QIODevice::WriteOnly | QIODevice::Truncate);
char data[SIZE];
int nHeadSize = sizeof(WaveHeader);
char* dataHead = new char[nHeadSize];
int nReadHD = file.read(dataHead, nHeadSize);
qint64 fileSize = file.size();
qint64 seekPos = fileSize / 5; // 文件的起始位置
// 11K、22K等的WAV文件要从数据的偶数字节截取才行。
// 而8、16K等可从任意位置截取。
// 因此将截取位置点调整在偶数就可以了。
if(0 != seekPos % 2)
seekPos -= 1;
file.seek(seekPos);
// file.seek(8024010);
qDebug()<<file.pos();
WaveHeader* pHead = (WaveHeader*)dataHead;
pHead->data_chkLen = fileSize / 2 - seekPos; // 保存文件长度
fileSave.write(dataHead, nHeadSize);
// 文件的终止位置 fileSize / 2
for (int i = 0; i < (fileSize / 2); i++)
{
int nLen = file.read(data, SIZE);
if(nLen > 0)
fileSave.write(data, SIZE);
else
break;
}
fileSave.close();
file.close();
delete dataHead;
return a.exec();
}