当前位置: 澳门新濠3559 > 操作系统 > 正文

5、发送文件大小和MD5值给客户端,如果文件有密

时间:2019-12-21 19:57来源:操作系统
想做个程序,目标是在后台扫描所有wps文件,判断是否存在密码,如果不存在则自动加一个密码,无须用户干预。存在问题:用workbooks.open打开时,如果文件有密码则老是提示用户输入

想做个程序,目标是在后台扫描所有wps文件,判断是否存在密码,如果不存在则自动加一个密码,无须用户干预。存在问题:用workbooks.open打开时,如果文件有密码则老是提示用户输入;想用workbooks.haspassword判断,则必须先打开文件;

FTP server

版权声明:若无来源注明,Techie亮博客文章均为原创。 转载请以链接形式标明本文标题和地址:
本文标题:Qt-excel文件操作方法     本文地址:

1.excel文件和工作簿

1、读取文件名

文章目录

excel文件就是excel工作簿
Workbooks 工作簿集合,泛指excel文件或工作簿
Workbooks("A.xls"),名称为A的excel工作簿

2、检测文件是否存在

  • 1. Qt-QAxObject
  • 2. 与excel com连接的方法
  • 3. Excel基本操作
  •  3.1. excel文件操作
  •  3.2. sheet工作表操作
  •  3.3. 内容操作
  • 4. 其他
  •  4.1. 大数据量读取
  •  4.2. 大数据量写入
  •  4.3. 范例:一个完整的打开-读取-关闭的操作
 Sub t1()
      Workbooks("A.xls").Sheets(1).Range("a1") = 100
   End Sub

3、打开文件

1. Qt-QAxObject

QAxObject是Qt提供的包装COM组件的类,通过COM操作Excel需要使用QAxObject类,使用此类还需要在pro文件增加“QT += axcontainer”

QAxObject的具体说明请见帮助文档

workbooks(2),按打开顺序,第二个打开的工作簿。

4、检测文件大小(告诉客户端发送文件的大小)

2. 与excel com连接的方法

  1. #include <QAxObject> //注意包含此头文件,同时在pro增加QT+= axcontainer
  2. QAxObject *excel = new QAxObject(this);//建立excel操作对象
  3. excel->setControl("Excel.Application");//连接Excel控件
  4. excel->dynamicCall("SetVisible (bool Visible)","false");//设置为不显示窗体
  5. excel->setProperty("DisplayAlerts", false);//不显示任何警告信息,如关闭时的是否保存提示
  6. excel->dynamicCall(?"Quit(void)"?);//关闭excel程序,操作完成后记着关闭,由于是隐藏的看不到,不关闭进程会有很多excel.exe
  7. //关闭excel程序之前记着先关闭.xls文件,具体见后续内容:workbook->dynamicCall("Close(Boolean)", false); //关闭文件

  8. Excel基本操作


下面只介绍主要读写操作的方法,若需要修改单元格格式等操作,请看“Excel VBA参考手册.chm”或者其他类似资料

手册分享地址: 链接: 密码: dnik

Sub t2()
     Workbooks(2).Sheets(2).Range("a1") = 200
  End Sub

5、发送文件大小和MD5值给客户端,MD5

3.1. excel文件操作

获取当前工作簿的集合

  1. QAxObject *workbooks = excel->querySubObject("WorkBooks");//获取工作簿(excel文件)集合

新建一个工作簿

  1. workbooks->dynamicCall("Add");//新建一个工作簿
  2. QAxObject *workbook = excel->querySubObject("ActiveWorkBook");//获取当前工作簿

打开一个已有的工作簿

  1. QString excel_file_path = "XXXX.xlsx";
  2. QAxObject* workbook = workbooks->querySubObject("Open(const QString&)", excel_file_path);

保存工作簿

  1. workbook->dynamicCall("Save()"); //保存文件
  2. workbook->dynamicCall("Close(Boolean)", false); //关闭文件
  3. excel->dynamicCall(?"Quit(void)"?);//关闭excel

另存为工作簿

  1. //用QDir::toNativeSeparators, 将路径中的"/"转换为"",否则无法保存,/只是qt中可以识别
  2. workbook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(excel_file_path));
  3. workbook->dynamicCall("Close (Boolean)", false); //关闭文件
  4. excel->dynamicCall(?"Quit(void)"?);//关闭excel

ActiveWorkbook ,当打开多个excel工作簿时,你正在操作的那个就是ActiveWorkbook(活动工作簿)

6、等待客户端确认(防止粘包)

3.2. sheet工作表操作

下面的代码用到的workbook都是上面工作簿操作后得到的,也就是对某一个工作簿(excel文件)进行操作

获取所有工作表

  1. QAxObject *worksheets = workbook->querySubObject("Sheets");

根据序号获取某个工作表,序号顺序就是excel打开后下方的排序

  1. QAxObject *worksheet = worksheets->querySubObject("Item(int)",1);

获取表中的行数列数

  1. QAxObject* usedrange = worksheet->querySubObject("UsedRange");//sheet范围
  2. int intRowStart = usedrange->property("Row").toInt();//起始行数
  3. int intColStart = usedrange->property("Column").toInt(); //起始列数
  4. QAxObject *rows, *columns;
  5. rows = usedrange->querySubObject("Rows");//行
  6. columns = usedrange->querySubObject("Columns");//列
  7. int intRow = rows->property("Count").toInt();//行数
  8. int intCol = columns->property("Count").toInt();//列数

Thisworkbook,VBA程序所在的工作簿,无论你打开多少个工作簿,无论当前是哪个工作簿是活动的,thisworkbook就是指代码所在的工作簿。

7、开始边读边发数据

3.3. 内容操作

数据内容操作-获取单元格-基于坐标

  1. QAxObject* cell = worksheet->querySubObject("Cells(int, int)", i, j);

数据内容操作-获取单元格-基于行列名称

  1. QAxObject* cell = worksheet->querySubObject("Range(QVariant, QVariant)", "A1");

数据内容操作-读单元格内容

  1. QVariant cell_value = cell->property("Value");

数据内容操作-写单元格内容

  1. cell->setProperty("Value", "内容");

  2. 其他


2.工作簿窗口

8、发送完整的MD5

4.1. 大数据量读取

读取所有单元格内容-数据量大请使用此方式,只需要进行一次操作即可读取所有内容到内容,避免重复每个单元格进行QAxObject操作

  1. QVariant var;
  2. QAxObject *usedRange = sheet->querySubObject("UsedRange");//获取用户区域范围
  3. if(NULL == usedRange || usedRange->isNull()) {
  4. return var;
  5. }
  6. var = usedRange->dynamicCall("Value");//读取区域内所有值
  7. delete usedRange;

此时结果以QVariant保存,需要自行转换成QList<QList<QVariant>>

  1. QList<QList<QVariant>> excel_list;
  2. auto rows = var.toList();
  3. for(auto row:rows) {
  4. excel_list.append(row.toList());
  5. }

Windows("A.xls"),A工作簿的窗口,使用windows可以设置工作簿窗口的状态,如是否隐藏等。

9、关闭服务器

4.2. 大数据量写入

大数据以QList<QList<QVariant>>存储,与读取类似,此处需要先指定区域范围

  1. QAxObject *user_range = this->sheet->querySubObject("Range(const QString&)","A1:D100");//范围

然后写入数据

  1. range->setProperty("Value", var);//需要将QList<QList<QVarient>>转换为QVarient
     Sub t3()
        Windows("A.xls").Visible = False
     End Sub

     Sub t4()
        Windows(2).Visible = True
     End Sub

socket收发文件,服务器端打开并发送文件,客户端接收并存储文件;这样就能实现文件的传输功能。

4.3. 范例:一个完整的打开-读取-关闭的操作

  1. QString excel_file_path = QDir::currentPath()+"/a.xlsx";
  2. excel_file_path = QDir::toNativeSeparators(excel_file_path);
  3. QAxObject *excel = new QAxObject(this);//建立excel操作对象
  4. excel->setControl("Excel.Application");//连接Excel控件
  5. excel->setProperty("Visible", true);//显示窗体看效果
  6. excel->setProperty("DisplayAlerts", true);//显示警告看效果
  7. QAxObject *workbooks = excel->querySubObject
  8. ("WorkBooks");//获取工作簿(excel文件)集合
  9. workbooks->dynamicCall("Open(const QString&)", excel_file_path);
  10. QAxObject *workbook = excel->querySubObject("ActiveWorkBook");
  11. QAxObject *worksheet = workbook->querySubObject("WorkSheets(int)",1);
  12. QAxObject *usedRange = worksheet->querySubObject("UsedRange");
  13. QVariant var = usedRange->dynamicCall("Value");//这里是所有的内容
  14. workbook->dynamicCall( "Close(Boolean)", false );
  15. excel->dynamicCall( "Quit(void)" );
  16. delete excel;

注意:
1、此范例为了看到效果吧窗口和警告设置为了显示,请自行改为false
2、excel所有操作均是通过QAxObject 进行COM组件的操作,包括打开文件也是,所以路径必须传递完整路径,不能传递相对路径
3、QAxObject自身会维护new出的空间,直接delete第一个QAxObject 即可
4、所有内容保存在var的变量中
5、上述操作均为判断返回值,若文件不存在后续内容会报错

 

3.判断A.Xls文件是否存在

os模块中的os.path.isfile()和os.path.exists():

    Sub W1()
     If Len(Dir("d:/A.xls")) = 0 Then   'dir  返回文件的名称,括号里面为文件的路径'
       MsgBox "A文件不存在"
     Else
       MsgBox "A文件存在"
     End If
   End Sub

    os.path.isfile()是用来判断文件是否存在的,只能判断文件,不能判断目录,如下所示:

4 判断A.Xls文件是否打开

    判断目录:

    Sub W2()
     Dim X As Integer
      For X = 1 To Windows.Count   '已经打开的窗口数量'
        If Windows(X).Caption = "A.XLS" Then
          MsgBox "A文件打开了"
          Exit Sub
        End If
      Next
    End Sub

 

  1. excel文件新建和保存
import os
file_path = os.path.abspath(__file__)
print(os.path.isfile('/home/zhuzhu/第八天'))
print(os.path.exists("/home/zhuzhu/第八天"))
输出如下:
False
True

 

  Sub W3()
     Dim wb As Workbook  ‘定义变量为工作簿’
     Set wb = Workbooks.Add   ‘看到set说明变量是一个对象变量’
       wb.Sheets("sheet1").Range("a1") = "abcd"
     wb.SaveAs "D:/B.xls"
  End Sub

    从上面代码可以看出,isfile()是判断文件是否存在,不能够判断目录是否存在,而exists()能够判断目录是否存在。

6.excel文件打开和关闭

    判断文件:

Sub w4()
   Dim wb As Workbook
   Set wb = Workbooks.Open("D:/B.xls")
   MsgBox wb.Sheets("sheet1").Range("a1").Value
   wb.Close False ‘false关闭不保存’
End Sub
import os
file_path = os.path.abspath(__file__)
print(os.path.isfile('file_test'))
print(os.path.exists("file_test"))
运行结果如下:
True
True

7.excel文件保存和备份

    从上面代码可以看出,isfile()和exists()都能够判断文件是否存在;

   Sub w5()
      Dim wb As Workbook
      Set wb = ThisWorkbook
      wb.Save
      wb.SaveCopyAs "D:/ABC.xls"
   End Sub

    从上面我们得出如下结论,isfile()只能判断文件是否存在,不能够判断目录是否存在;而exists()能够判断文件和目录是否存在。

  1. excel文件复制和删除

    其实hashlib就是防止破解的,用户该输入什么就输入什么,只是按照要求的方式,把用户输入的密码加密,以别人看不懂的格式进行存储,防止暴力破解。对客户本身来说是没有影响的,只是表现的方式不一样而已。

    加密:

   Sub W6()
      FileCopy "D:/ABC.XLS", "E:/ABCd.XLS"
      Kill "D:/ABC.XLS"
   End Sub
import hashlib
def encryption():
    '''
    对用户输入的内容进行加密
    :return:
    '''
    while True:
        passwrod = input("请输入您的密码>>:")
        m = hashlib.md5()
        m.update(passwrod.encode('utf-8'))
        print("在系统存储的密码如下:%s" %m.hexdigest())

encryption()

    上面代码是对用户输入进行加密处理,加密之后,返回加密后的暗文,其实加密,就是不想别人看到密码原始的样子,如下所示:

请输入您的密码>>:asdfasfd
在系统存储的密码如下:7b4dafa43458d3a6a232afdd184ecb53
请输入您的密码>>:afdsasfd
在系统存储的密码如下:5ae8c46414716d2b606ff7c7109c6b1b
请输入您的密码>>:asfda
在系统存储的密码如下:933a3cde50f232f9f2eb3ef106a7b2d4
请输入您的密码>>:dfasdf
在系统存储的密码如下:991d4860883cbdec8effc3f3a3b71bce
请输入您的密码>>:asdf
在系统存储的密码如下:912ec803b2ce49e4a541068d495ab570
请输入您的密码>>:adsf
a在系统存储的密码如下:05c12a287334386c94131ab8aa00d08a
请输入您的密码>>:sdf
在系统存储的密码如下:912ec803b2ce49e4a541068d495ab570
请输入您的密码>>:asdf
as在系统存储的密码如下:912ec803b2ce49e4a541068d495ab570
请输入您的密码>>:df
在系统存储的密码如下:912ec803b2ce49e4a541068d495ab570
请输入您的密码>>:asdf
在系统存储的密码如下:912ec803b2ce49e4a541068d495ab570
请输入您的密码>>:adsf
在系统存储的密码如下:05c12a287334386c94131ab8aa00d08a
请输入您的密码>>:adfs
在系统存储的密码如下:6a09965fb1ad7f14539e569c264b15ef
请输入您的密码>>:sadf
在系统存储的密码如下:fe6d1fed11fa60277fb6a2f73efb8be2
请输入您的密码>>:12346
在系统存储的密码如下:a3590023df66ac92ae35e3316026d17d
请输入您的密码>>:123456a
在系统存储的密码如下:9cbf8a4dcb8e30682b927f352d6559a0
请输入您的密码>>:adfa
d在系统存储的密码如下:4ac174730d4143a119037d9fda81c7a9
请输入您的密码>>:fas
在系统存储的密码如下:5a5dc3936c05c32e61aa539e7ffb40c0
请输入您的密码>>:fdasfd
a在系统存储的密码如下:a87b8bcbfe5a5030fc01e7688e2bbc94
请输入您的密码>>:sdf
在系统存储的密码如下:912ec803b2ce49e4a541068d495ab570
请输入您的密码>>:asdf
a在系统存储的密码如下:912ec803b2ce49e4a541068d495ab570
请输入您的密码>>:sdf
在系统存储的密码如下:912ec803b2ce49e4a541068d495ab570

    上面,用户输入密码,转换成MD5密码值,这样就是别人看到数据库里面的密码,也不能反解用户的密码,保护用户的隐私。

    os.stat(path)判断文件大小,如下所示:

import hashlib,os
file_size = os.stat('file_test')
print(file_size)
print(file_size.st_size)
运行结果如下:
os.stat_result(st_mode=33204, st_ino=17320086, st_dev=64768, st_nlink=1, st_uid=1000, st_gid=1000, st_size=150, st_atime=1503270341, 
st_mtime=1503270327, st_ctime=1503270327)
150

    上面文件中,我们使用stat()来判断文件大小,存储属性,取其中的文件大小的属性,得到结果。

    服务器端:

import socket,os,time,hashlib
server = socket.socket()
server.bind(("localhost",9998))
server.listen()
while True:
    conn,addr = server.accept()
    print("new conn:",addr)
    while True:
        print("等待新指令")
        data = conn.recv(1024)
        if not data:
            print("客户端已经断开")
            break
        cmd,filename = data.decode().split()    #data是一个byte形式,先转换
        print(filename)
        if os.path.isfile(filename):     #isfile是判断文件是否存在
            f = open(filename,'rb')      #以字节码形式打开
            m = hashlib.md5()
            file_size = os.stat(filename).st_size
            '''hashlib不能直接对文件进行加密'''
            conn.send(str(file_size).encode('utf-8'))
            conn.recv(1024)   #等待客户端接收成功,以便下一次发送   wait for ack
            '''循环发送,读一行发一行'''
            for line in f:
                # m.update(line)
                conn.send(line)    #发送文件,循环完成之后发送MD5
            # print("file md5",m.hexdigest())
            f.close()

        print('send done')

server.close()

    上面服务器端是接收客户端文件名的指令,然后打开文件,并发送文件的内容,逐行读取并发送给客户端。

    客户端:

import socket
client = socket.socket()
client.connect(("localhost",9998))

while True:
    cmd = input(">>:").strip()
    if len(cmd) == 0:continue
    if cmd.startswith('get'):
        '''代表接收文件'''
        client.send(cmd.encode('utf-8'))
        server_response = client.recv(1024)   #接收文件大小
        print("server response:",server_response)   #打印文件大小
        client.send(b"ready to recv file")
        file_total_size = int(server_response.decode())
        received_size = 0
        filename = cmd.split()[1]
        f = open(filename+".new",'wb')    #文件名不能一样,不然会覆盖之前我文件名
        while received_size < file_total_size:
            data = client.recv(1024)
            received_size += len(data)
            f.write(data)
            # print(file_total_size,received_size)
        else:
            print("file recv done",received_size,file_total_size)
            f.close()

client.close()

    客户端是用来接收数据,并存储到文件中,数据在socket()中的传输,其实就是接收和发送两个步骤,在传输的过程中,只能接收和发送字节,并且两次发送一定要防止粘包,因为发送数据是同步的,因此要客户端完全接收之后,服务器端再进行下一次的发送。

    下面进行MD5验证,加入MD5验证,传输速度会变慢:

编辑:操作系统 本文来源:5、发送文件大小和MD5值给客户端,如果文件有密

关键词: