利用python+qt编写阿里云OSS文件管理系统上

  • 梦影无痕丶
  • 9 Minutes
  • February 22, 2018

前言

由于markdown中博客的图片需要存放在云端,获取云端链接来插入博客,第一想法就是使用阿里云的OSS存储,但是阿里云OSS中的文件操作要通过管理控制台,就很不方便。一开始选择使用了图床的网页工具,他提供了多种云端托管上传,也试着用了一下,网页工具还是有点不方便,就想着自己做一个简易的阿里云文件上传管理系统。
前面也看了阿里云OSS的帮助网页,整理了相关的python命令,可以用其打包成一个OSS操作类,再利用qt搭建GUI界面。想来难度也不是很高,就试着做了一下。

环境准备

开发工具:VS2015+python3.6+pyqt5

安装pyqt5

在cmd窗口输入

pip install pyqt5
pip install pyqt5-tools

或者使用conda 安装,

conda install pyqt
conda install pyqt5-tools

运行 python,输入

from PyQt5 import QtWidgets

没有报错,说明pyqt安装成功,对于重装的pyqt5,可能会遇到

DLL load failed: 找不到指定的程序

这时,先运行

pip uninstall pyqt5

卸载原来的pyqt重新安装即可。如果还是失败,把conda也卸了重装。

安装pyinstaller

pyinstall 是一个可以将py文件打包成exe文件的工具,在完成项目阶段性开发,可以利用pyinstall将文件打包发布。用conda安装提示找不到包,换 pip 安装即可:

pip install pyinstaller

VS2015准备

这里需要给VS2015添加两个外部工具。选择 工具->外部工具

添加 Qt Designer

用于绘制UI,路径为

{python安装目录}\Lib\site-packages\pyqt5-tools\designer.exe

参数

$(ItemFileName).ui

初始目录

$(ItemDir)

添加 pyuic5

用于将绘制的 UI 文件转化为python代码,路径为

{python安装目录}\Scripts\pyuic5.exe

参数

$(ItemFileName).ui -o $(ItemFileName).py

初始目录

$(ItemDir)

添加 pyinstaller

用于打包工程,路径为

{python安装目录}\Scripts\pyinstaller.exe

参数

-F $(ItemFileName).py

初始目录

$(ItemDir)

创建项目

文件->新建->项目,选择 Python Application。

新建 aliyunManage.py 。在其中编写管理阿里云OSS的操作命令。
新建 appUI.py 。在其中编写窗口创建,逻辑实现。
新建 aliyunOSS.ui 。使用 Qt Designer 绘制UI窗口,完成后利用pyuic5转换成 aliyunOSS.py。

操作命令类编写

json 操作

这里将用户信息用Json文件存储在磁盘上,以便于用户信息修改。
新建一个 Json 文件,命名为 data.json 。添加用户信息:

{
    "AccessKeyId": "你的AccessKeyId", 
    "AccessKeySecret": "你的AccessKeySecret", 
    "EndPoint": "你的EndPoint", 
    "bucket": "你的bucket名"
}

python 提供了 Json 的操作类,在这里先导入

import json

json 类中主要有两个重要函数

json.dump(数据,文件)  #文件读取
数据=json.load(文件) #文件写入

类代码:

class jsonOp(object):
    data = {}
    def __init__(self):
        self.read()

    def write(self):
        with open('data.json','w') as fout:
            json.dump(self.data,fout)

    def read(self):
        with open('data.json','r') as fin:
            self.data=json.load(fin)

阿里云OSS操作

操作之前已经讲过,直接贴代码了:

class OSSOp(object):
    '''
    初始化,获得bucket与service,其中servic可用于操作bucket
    '''
    def __init__(self):      
        jsonData=jsonOp()
        auth = oss2.Auth(jsonData.data['AccessKeyId'], jsonData.data['AccessKeySecret'])
        self.bucket = oss2.Bucket(auth, jsonData.data['EndPoint'], jsonData.data['bucket'])
        self.service = oss2.Service(auth, jsonData.data['EndPoint'])

    '''
    上传文件
    '''
    def putfile(self,putname,filename):
        try:
            self.bucket.put_object_from_file(putname, filename)
        except Expection:
            return False
        else:
            return True

    '''
    上传文件
    '''
    def downloadfile(self,filename):
        try:
            bucket.get_object_to_file(filename, filename, progress_callback=percentage)
        except Expection:
            return False
        else:
            return True
        '''

    下载文件
    '''
    def downloadfile(self,filename,savefile_path):
        try:
            self.bucket.get_object_to_file(filename, savefile_path, progress_callback=self.percentage)
        except Expection:
            return False
        else:
            return True

    '''
    显示下载文件百分比,cmd窗口查看
    '''
    def percentage(self,consumed_bytes, total_bytes):
        if total_bytes:
            rate = int(100 * (float(consumed_bytes) / float(total_bytes)))
            print('\r{0}% '.format(rate), end='')
            sys.stdout.flush()

    '''
    查看bucket中文件,上限为100
    '''
    def showfile(self):
        filename=[]
        for b in islice(oss2.ObjectIterator(self.bucket), 100):
            filename.append(b.key)
        return filename

    '''
    查看bucket
    '''
    def showBucket(self):
        print([b.name for b in oss2.BucketIterator(self.service)])


    '''
    删除文件
    '''
    def deletefile(self,filename):
        try:
            self.bucket.delete_object(filename)
        except Exception:
            return False
        else:
            return True

在文件结尾加入测试代码:

if __name__ == '__main__':
    oss=OSSOp()
    files=oss.showfile()
    print(files)

代码用于打印 bucket 中的文件

UI界面及接口槽设计

打开 alyunOSS.ui, 选择 工具->Qt Designer 打开UI设计工具

新建一个Main Window,

因为是小工程,菜单栏没什么用处,选中删除。
再从 Containers 中拖一个 Tab Widget,利用 Tab Widget 作为框架

基本布局是这样:

这样

和这样

控件命名是这样:

信号和槽是这样

这里要提几点

信号和槽的连接

在工具栏有一个 Edit Signals/Solts,点击他:

然后就可以拖动控件到链接到制定控件了,还可以自定义信号和槽。例如我拖到 downloadBtn 连接到 MainWindow,会自动弹出下图,左边 downloadBtn 由于是实例化 QPushButton 无法更改,右边 MainWindow 是自己定义的,继承了 QMainWindow,可以添加槽,但是不能删除原有槽,

点击 Edit,然后加号添加槽,更改名字后需要再次点击加号,否则无法改名,不知是bug还是什么缘故,没有细究,将就着用了。

导入py文件

UI文件设计好保存后,回到 VS2015 中,选择 工具->pyuic5 到处成 py 文件。

如果想要运行看看UI效果,可以先将信号槽连接注释,

然后在生成的 aliyunOSS.py 后面加如代码:

if name == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

注意,每次导出后 py 文件都会重置,所以自己在里面的修改是无效的。

也是因为这个,所以在设计过程中把 UI 和逻辑部分分离,,,下篇文件将描述逻辑部分设计。