工作變動(dòng)開始接觸qt,涉及到qt讀文件相關(guān)業(yè)務(wù),簡單整理一下qt讀文件幾種方式,后面發(fā)現(xiàn)有其他的再新增
1:使用qt讀文件顯示在界面的時(shí)候發(fā)現(xiàn)特別慢(實(shí)際是界面顯示過多/日志打印導(dǎo)致)
測試demo的方式歸納匯總幾種讀qt文件的方法:
1:獲取文件源按鈕,并打印獲取到的相關(guān)文件名
2:使用qfile直接讀文件,顯示耗時(shí)時(shí)間
3:使用qdatastream讀文件,顯示耗時(shí)時(shí)間
4:使用qtextstrean讀文件,顯示耗時(shí)時(shí)間
5:使用內(nèi)存映射 Qfile::map 內(nèi)存映射讀文件,這里的map實(shí)際是Qfile的基類中的
2:qflie直接讀文件
按行讀取,read按字節(jié)讀取,readAll讀全部幾種方式
void frmReadFile::on_qfileReadFileButton_clicked()
{
//使用qfile readline /readAll
QFile file_read(m_filename);
if(!file_read.exists()) {
return;
}
if (!file_read.open(QIODevice::ReadOnly)) {
QMessageBox::warning(this, "警告", "文件打不開!");
return;
}
//按行讀取的方式
// QByteArray readdata_array;
// while(!file_read.atEnd())
// {
// readdata_array = file_read.readLine();
// //真正的耗時(shí)在顯示在控件上 如果增加顯示在控件上 可能需要耗時(shí)22s
// ui->printTextEdit->append(readdata_array.toHex(' '));
// qDebug()<<"read file size:"<<readdata_array.size();
// readdata_array.clear();
// }
//read讀取特定字節(jié)
int readlength = 0;
QByteArray byte_data;
byte_data.resize(1000);
while((readlength=file_read.read(byte_data.data(),1000))!=0) // 一次讀進(jìn)1000個(gè)字節(jié)(讀進(jìn)1000個(gè)字節(jié),length==1000),當(dāng)剩余字節(jié)數(shù)小于1000時(shí),length等于剩余字節(jié)數(shù)
{
this->append(QString(byte_data.toHex(' ')));
}
//readall直接讀取全部內(nèi)容
// QByteArray readdata_array;
// file_read.seek(0);
// readdata_array= file_read.readAll();
// ui->printTextEdit->append(readdata_array.toHex(' '));
// qDebug()<<"read file size:"<<readdata_array.size() <<"data is:"<<readdata_array.toHex(' ');
// readdata_array.clear();
file_read.close();
}
3:qTextStream讀文件
借助readLine readAll read 可以實(shí)現(xiàn)文件讀取
通過用QElapsedTimer增加耗時(shí),分析出文件處理真正耗時(shí)在內(nèi)容顯示上。
寫時(shí)發(fā)現(xiàn)待處理問題:打開文件的方式,以及讀取顯示中文的demo。
void frmReadFile::on_qTextStrReadFileButton_clicked()
{
QFile file_read(m_filename);
if(!file_read.exists()) {
return;
}
if (!file_read.open(QIODevice::ReadOnly)) {
QMessageBox::warning(this, "警告", "文件打不開!");
return;
}
//讀取并顯示在控件上 耗時(shí)7s
QElapsedTimer lost_time;
lost_time.start();
QString read_data= "";
QTextStream out(&file_read);
while(!out.atEnd())
{
read_data += out.readLine();
// ui->printTextEdit->append(read_data); //耗時(shí)7s
}
QString qfile_lost_time = "qtextstream 讀取文件耗時(shí):";
qfile_lost_time += QString::number(lost_time.elapsed());
qfile_lost_time += "毫秒";
ui->TestTextEdit->append(qfile_lost_time);
//先讀取再顯示的方案 讀取耗時(shí)59ms 主要顯示也都是亂碼
//這里如果轉(zhuǎn)成16進(jìn)制進(jìn)行輸出 內(nèi)存占用太大太大 會(huì)導(dǎo)致程序卡死
// ui->printTextEdit->append(read_data.toLatin1().toHex());
ui->printTextEdit->append(read_data);
file_read.close();
}
4:qdatastream讀文件
可以通過readBytes, readRawData實(shí)現(xiàn)文件的讀取
寫時(shí)發(fā)現(xiàn)待處理問題:遇到過open文件時(shí)選擇打開方式 如果以Text方式打開,流顯示換行符號(hào)會(huì)是兩個(gè)字節(jié),所以在處理讀文件時(shí),open函數(shù)的參數(shù)要注意
//使用qdatastream進(jìn)行讀文件
//耗時(shí)挺短的 讀文件并不怎么耗時(shí) 耗時(shí)在處理顯示上
void frmReadFile::on_qdataStrReadFileButton_clicked()
{
QFile file_read(m_filename);
if(!file_read.exists()) {
return;
}
if (!file_read.open(QIODevice::ReadOnly)){
QMessageBox::warning(this, "警告", "文件打不開!");
return;
}
QElapsedTimer lost_time;
lost_time.start();
QDataStream out(&file_read);
QByteArray read_data;
read_data.resize(file_read.size());
//一次性讀取內(nèi)容過多 導(dǎo)致文件讀不出來
while(!out.atEnd())
{
out.readRawData(read_data.data(), file_read.size());
}
QString qfile_lost_time = "qdatastream 讀取文件耗時(shí):";
qfile_lost_time += QString::number(lost_time.elapsed());
qfile_lost_time += "毫秒";
ui->TestTextEdit->document()->setMaximumBlockCount(100);
ui->TestTextEdit->append(qfile_lost_time);
qDebug()<<"read file size:"<<read_data.size();
//這里進(jìn)行顯示的時(shí)候如果過大總會(huì)崩潰 ===》內(nèi)容過大到界面顯示的問題
ui->printTextEdit->document()->setMaximumBlockCount(100);
ui->printTextEdit->append(read_data.toHex(' '));
lost_time.restart();
//TODO 1:研究一下通過信號(hào)觸發(fā)容器的寫入 2:研究一下QByteArray轉(zhuǎn)成帶空格的耗時(shí)
file_read.close();
}
5:內(nèi)存映射的方式讀文件
其實(shí)就是把指針映射到文件的對(duì)應(yīng)位置,然后相關(guān)的操作就和操作內(nèi)存指針一樣了。
主要用到了 QFileDevice 類的 map 和unmap
//內(nèi)存映射的方法讀文件
void frmReadFile::on_qmapReadFileButton_clicked()
{
//采用內(nèi)存映射的方法進(jìn)行
QFile file_read(m_filename);
if (!file_read.open(QIODevice::ReadOnly))
{
QMessageBox::warning(this, "警告", "文件打不開!");
return;
}
QElapsedTimer lost_time;
lost_time.start();
int file_size = file_read.size();
uchar* ptr = file_read.map(0, file_read.size());
uchar* flag_ptr = ptr;
//這里先關(guān)閉文件對(duì)讀文件不影響
int temp = 0;
QByteArray flag_data;
flag_data.resize(1000);
while(temp < file_size)
{
memcpy(flag_data.data(), flag_ptr+temp, 1000);
temp += 1000;
//這里對(duì)數(shù)據(jù)進(jìn)行處理
//TODO 這里的打印會(huì)導(dǎo)致qt工具打印過多日志 其他工具崩潰
// qDebug()<<"file map data0 is"<<flag_data;
// ui->printTextEdit->append(flag_data.toHex());
//這里如果讀取文件過大 也會(huì)讓程序占用的內(nèi)存大
this->append(QString(flag_data.toHex(' ')));
}
if(temp>file_size)
{
memcpy(flag_data.data(), flag_ptr+(file_size-file_size%1000), file_size%1000);
qDebug()<<"file map data1 is"<<flag_data;
ui->printTextEdit->append(flag_data.toHex(' '));
// this->append(QString(flag_data.toHex(' ')));
}
QString qfile_lost_time = "qfile map 讀取文件耗時(shí):";
qfile_lost_time += QString::number(lost_time.elapsed());
qfile_lost_time += "毫秒";
qfile_lost_time += QString::number(file_size/1000);
qfile_lost_time += "行";
ui->TestTextEdit->append(qfile_lost_time);
file_read.unmap(ptr);
if(ptr!=NULL)
{
ptr = NULL;
qDebug()<<"umap is not null";
}
file_read.close();
}
6:總結(jié)
這些demo測試的初衷是,初次接觸qt,要處理一批大文件后,進(jìn)行界面的顯示,但是發(fā)現(xiàn),讀取大文件時(shí),有崩潰,耗時(shí)的問題。
排查耗時(shí)崩潰問題的原因,有懷疑過是讀文件的耗時(shí),所以做了簡單demo測試,最后發(fā)現(xiàn)是字符處理內(nèi)存增加,qDebug日志記錄,通過ui進(jìn)行界面顯示過大內(nèi)容導(dǎo)致的耗時(shí),甚至崩潰。
在整理回頭整理demo的過程,以及最近實(shí)際過程中遇到的小問題,發(fā)現(xiàn)可以整理的點(diǎn):
1:open的時(shí)候,打開方式按默認(rèn),文本方式,流的方式打開,對(duì)后面文件處理有影響(例如,以文本方式打開,但是用qdatastream處理流的時(shí)候發(fā)現(xiàn),換行符變成了兩個(gè)字符)。
2:幾種方式排查后,讀文件并不耗時(shí),可以整理幾種讀文件方式的原理。文章來源:http://www.zghlxwxcb.cn/news/detail-660332.html
3:研究幾種讀文件后,字符處理中文顯示問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-660332.html
到了這里,關(guān)于qt初入門1:qt讀文件的幾種方式簡單整理的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!