zoukankan      html  css  js  c++  java
  • Pyqt 获取打包二进制文件中的资源

    记得有一次打开一个单独exe程序,点击btn中的一个帮助说明按钮,在同级目录下就多出一个help.chm 文件并自动打开。

    那这个exe肯定是把help.chm 打包到exe中,当我触发“帮助”按钮的时候另存为help.chm 并打开该文件。

    所以我在想,Pyqt打包资源是否也可以另存为后打开资源中的文件呢?然后就有了下文

    一、 生成资源文件

    我们先找几个资源文件

    比如:

    用Qt Designer中的资源浏览器把资源素材添加并保存为resexe.qrc 文件

    resexe.qrc文件:

    <RCC>
      <qresource prefix="exe">
        <file>aaa/ResHacker3.5.exe</file>
      </qresource>
      <qresource prefix="chm">
        <file>aaa/PyQt4_Tutorial.chm</file>
      </qresource>
      <qresource prefix="txt">
        <file>aaa/texta.txt</file>
      </qresource>
       <qresource prefix="mp3">
        <file>aaa/apples.mp3</file>
      </qresource>
    </RCC>

    将qrc资源文件转换为py

    pyrcc4 -o resexe.py  resexe.qrc

    二、编写逻辑代码

     用Python读取保存二进制文件是这样的:

    #读取资源文件                                     
    originalfile = open('F:/QQ.exe','rb')
    filedata = originalfile.read()
    originalfile.close()
    #指定为字节类型
    savedata = bytearray(filedata)
    savefile = open('C:/QQ_res.exe','wb')
    savefile.write(savedata)
    savefile.close()

    但在Pyqt中py原生的open() 方法是找不到文件的:
    因为Qt qrc转换的资源必须要用":"开始引用,例如:

    self.setWindowIcon(QIcon(':qq.ico'))

    以下代码是错误的:

    originalfile = open(':mp3/aaa/apples.mp3','rb')
    filedata = originalfile.read()
    originalfile.close()
    savedata = bytearray(filedata)
    savefile = open('C:/apples.mp3','wb')
    savefile.write(savedata)
    savefile.close()

    报错:

    Traceback (most recent call last):
     originalfile = open(':mp3/aaa/apples.mp3','rb')
     IOError: [Errno 22] invalid mode ('rb') or filename: ':mp3/aaa/apples.mp3'

    所以直接使用Py的open()方法是无法获取Qt qrc资源文件的。

    要获取qrc里面的资源文件必须要使用Qt内置的QFile

    下面有两个方法

    • QFile的copy()方法
    QtCore.QFile.copy(':mp3/aaa/apples.mp3','C:/appless.mp3')

    可直接将资源文件copy到指定的目录

          QFile.copy文档:

    bool QFile.copy (self, QString newName)

    Copies the file currently specified by fileName() to a file called newName. Returns true if successful; otherwise returns false.

    Note that if a file with the name newName already exists, copy() returns false (i.e. QFile will not overwrite it).

    The source file is closed before it is copied.

    See also setFileName().

    bool QFile.copy (QString fileName, QString newName)

    This is an overloaded function.

    Copies the file fileName to newName. Returns true if successful; otherwise returns false.

    If a file with the name newName already exists, copy() returns false (i.e., QFile will not overwrite it).

    See also rename().

     

     

     

    • QFile的QIODevice.readAll() 
    originfiles = QtCore.QFile(':mp3/aaa/apples.mp3')
    originfiles.open(QtCore.QFile.ReadOnly)
    origindata = originfiles.readAll()
    savefiledata = bytearray(origindata)
    savefile = open('C:/appless.mp3', 'wb')
    savefile.write(savefiledata)
    savefile.close()

    QFile以只读模式打开资源':mp3/aaa/appless.mp3', readAll() 返回二进制QByteArray, 再通过Py的open() 以'wb'模式写入二进制数据

    QIODevice.readAll文档:

    object QIODevice.read (self, long maxlen)

    Reads at most maxSize bytes from the device into data, and returns the number of bytes read. If an error occurs, such as when attempting to read from a device opened in WriteOnly mode, this function returns -1.

    0 is returned when no more data is available for reading. However, reading past the end of the stream is considered an error, so this function returns -1 in those cases (that is, reading on a closed socket or after a process has died).

    See also readData(), readLine(), and write().

    QByteArray QIODevice.readAll (self)

    This is an overloaded function.

    Reads all available data from the device, and returns it as a QByteArray.

    This function has no way of reporting errors; returning an empty QByteArray() can mean either that no data was currently available for reading, or that an error occurred.

     完整代码如下:

    # -*- coding: utf-8 -*-
    '''
    下载打包资源文件中的资源
    '''
    
    from PyQt4 import QtCore, QtGui
    
    import sys, os
    
    reload(sys)
    sys.setdefaultencoding("utf-8")
    
    
    class Mwindow(QtGui.QDialog):
        def __init__(self):
            super(Mwindow, self).__init__()
            self.resize(100, 150)
            self.setWindowTitle(u'下载打包文件中的资源文件')
            self.down1 = QtGui.QPushButton(u'下载ResHacker')
            self.down2 = QtGui.QPushButton(u'下载PyQt4_Tutorial')
            self.down3 = QtGui.QPushButton(u'下载texta文本')
            self.down4 = QtGui.QPushButton(u'下载apples.mp3')
            self.checked = QtGui.QCheckBox(u'同时打开文件')
            self.checked.setCheckState(QtCore.Qt.Checked)
            mylayout = QtGui.QGridLayout()
            mylayout.addWidget(self.down1, 0, 0)
            mylayout.addWidget(self.down2, 0, 2)
            mylayout.addWidget(self.down3, 0, 1)
            mylayout.addWidget(self.down4, 1, 0)
            mylayout.addWidget(self.checked, 1, 2)
            self.setLayout(mylayout)
            self.connect(self.down1, QtCore.SIGNAL('clicked()'), self.download)
            self.connect(self.down2, QtCore.SIGNAL('clicked()'), self.download)
            self.connect(self.down3, QtCore.SIGNAL('clicked()'), self.download)
            self.connect(self.down4, QtCore.SIGNAL('clicked()'), self.download)
    
        def download(self):
    
            import resexe
    
            senderc = str(self.sender().text())
            downObject = ''
            extend = 'All Files (*.*)'
            if senderc.find('appl') > 0:
                downObject = ':mp3/aaa/apples.mp3'
                extend = 'mp3 Files (*.mp3)'
            if senderc.find('ResHacker') > 0:
                downObject = ':exe/aaa/ResHacker3.5.exe'
                extend = 'exe Files (*.exe)'
            if senderc.find('PyQt4_Tutorial') > 0:
                downObject = ':chm/aaa/PyQt4_Tutorial.chm'
                extend = 'chm Files (*.chm)'
            if senderc.find('text') > 0:
                downObject = ':txt/aaa/texta.txt'
                extend = ' Files (*.txt)'
    
            fileName = QtGui.QFileDialog.getSaveFileName(self, u"文件保存", "C:/", extend)
            if fileName:
                # 方法一
                # QtCore.QFile.copy(downObject,fileName)
                #方法二
                originfiles = QtCore.QFile(downObject)
                originfiles.open(QtCore.QFile.ReadOnly)
                origindata = originfiles.readAll()
                savefiledata = bytearray(origindata)
                savefile = open(fileName, 'wb')
                savefile.write(savefiledata)
                savefile.close()
    
                openfile = self.checked.isChecked()  #判断选择打开文件
                if openfile:
                    os.system(str(fileName))
                else:
                    QtGui.QMessageBox.question(self, (u'提示'), (u'保存成功'), QtGui.QMessageBox.Yes)
    
    
    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        mainWin = Mwindow()
        mainWin.show()
        sys.exit(app.exec_())

     三、将代码打包成二进制exe

    我们使用Pyinstaller打包

    if __name__ == '__main__':
        from PyInstaller.main import run
        params=['downloadres.py', '-F', '-w', '--icon=favicon.ico']
        run(params)

    生成downloadres.exe

    四、运行效果


    如果可以,接下来我们也可以做一个tcp获取网络资源并下载的Pyqt程序。

  • 相关阅读:
    Git常用命令大全
    前端开发常用正则表达式
    如何让360、遨游、猎豹等双核浏览器默认以webkit内核渲染网页?
    IE如何兼容placeholder属性
    利用sublime的snippet功能快速创建代码段
    浏览器内核总结
    display:inline-block引发的间隙问题解决办法
    常用的CSSreset整理
    input输入框的border-radius属性在IE8下的完美兼容
    详细讲解Android中的AbsListView的源码
  • 原文地址:https://www.cnblogs.com/dcb3688/p/4607956.html
Copyright © 2011-2022 走看看