QXlsx的private header message消除(替换QZip)

This is not a bug

在对比了几个Qt的excel工具以后,一开始想选一个尽量简单的,但是试用了以后,还是默默选择了Qxlsx,真香。
我是使用pri和源码直接添加到工程里,这样方便调试和问题出错,当然如果后期没有问题的话,可以考虑生成库的形式添加;
但是在每回项目编译的时候都会出现如下信息

Project MESSAGE: This project is using private headers and will therefore be tied to this specific Qt module build version.
Project MESSAGE: Running this project against other versions of the Qt modules may crash at any arbitrary point.
Project MESSAGE: This is not a bug, but a result of using Qt internals. You have been warned!

虽然不致命 但是还是感觉微微不爽,就像每回有个人在你耳边唠叨一样,于是决定干掉它。

网上查了一下原因,这是由于代码中添加了gui-private的私有库的原因,具体的成因咱不再这讨论,那么程序中有哪个地方用到了这个东西呢?
答案是QZipReader和QZipWriter,因为在xlsx的读取和输出的时候都要用到zip压缩,所以这里使用了Qt原生的zip方法,导致了我们需要添加gui-private。

zip

本来想使用minizip的方法进行替换,但是发现minizip需要编译链接libzip,唉,以前用的都是公司的老司机给我们编译好的工程,自己弄的时候才发现人家替你做了这么多。
还是pass了minizip,直到搜到这篇文章《呕心沥血成功消除QT私有方法的经验总结》 ,看来还是有不少强迫症同仁的。
里面介绍了使用zip utils的组件进行替换,只需要添加4个文件就搞定,而且使用起来也是相当方便,于是就大胆的拿来ctrl+C和ctrl+v。
zip utils的下载地址是Zip Utils - Clean, Elegant, Simple, C++/Win32

zip utils to windows

针对ZipReader和ZipWriter的修改,我不做过多的讲了,上面文章里写的很清楚了。我想说的是针对zip utils在windows下的编译问题;文章中的作者也说只是在linux下进行了使用,没有在windows里使用,所以我在进行编译的时候还是遇到了不少问题;

首先,对与zip utils中的头文件需要引入Windows.h,这样很多类型和函数才能识别;

#ifdef WIN32
#include <Windows.h>
#endif

再者就是在pri文件中需要引入User32库,不然会有一些函数因为找不到入口而报警;

win32
{
    LIBS += -lUser32
}

Character encoding

针对字符编码,文章的作者也是强调了,因为使用了tchar,所以使用不同的编码方式编译会有不同的问题,比如我使用的是unicode,所以对不同编码的编写要进行区分;其实在内部zip utils作者也是进行了转换的,原则多余文件的读写都是使用宽字节的处理方式,而内部内存的操作,则看使用者使用的是什么编码,针对zipreader和zipwriter的编写,进行了一些补完

void ZipReader::init()
{
    ZIPENTRY entry;
    GetZipItem(m_reader,-1,&entry);
    int nItems = entry.index;
    for(int zi=0; zi<nItems; zi++)
    {
        GetZipItem(m_reader,zi,&entry);
#ifdef UNICODE
        m_filePaths.append(QString::fromWCharArray(entry.name));
#else
        m_filePaths.append(QString::fromUtf8(entry.name));
#endif
    }
}
QByteArray ZipReader::fileData(const QString &fileName) const
{
    ZIPENTRY entry;
    int i=-1;
#ifdef UNICODE
     std::wstring strFile = fileName.toStdWString();
     FindZipItem(m_reader,strFile.c_str(),true,&i,&entry);
#else
     FindZipItem(m_reader,fileName.toUtf8().constData(),true,&i,&entry);
#endif

    if(entry.unc_size < 0 || i<0)
    {
        return QByteArray("");
    }

    char*pBuf = new char[entry.unc_size +1];
    QByteArray byteArray;
    UnzipItem(m_reader,i,pBuf,entry.unc_size);
    byteArray.append(pBuf,entry.unc_size);
    delete []pBuf;
    return byteArray;
}

这里不再一一列举,其原则都是进行字符集的宏定义区分。

还有一个问题就是使用的时候,对文件名和表格操作时的字符集问题,如果你使用qt+msvc,并且qt编辑器默认选择的是utf-8编码,那么在Qxlsx的helloworld测试历程中,使用如下测试内容,你将得到一堆乱码

    QXlsx::Document xlsxW;
    xlsxW.write("A1", "你好 Qt!"); // write "Hello Qt!" to cell(A,1). it's shared string.
    if ( xlsxW.saveAs("D:\\测试文.xlsx") ) // save the document as 'Test.xlsx'
    {
        qDebug() << "[debug] success to write xlsx file";
    }
    else
    {
        qDebug() << "[debug][error] failed to write xlsx file";
    }

正确的做法是在代码中存在中文的文件开头明确的指出使用的编码格式

#pragma execution_character_set("utf-8")

last

本篇改进主要针对的是windows下的工程使用,对于mingw应该也有借鉴意义,但是对于linux和mac 没有测试过,也希望c友们能够自行测试提交;
so 有兴趣的小伙伴自己上我的fork工程进行代码浏览吧https://github.com/vvck/QXlsx

posted @ 2021-07-07 10:37  chencarl  阅读(2224)  评论(0编辑  收藏  举报