【Python-利用动态二维码传输文件(二)】实现文件二进制读取、利用base64编码把文件拆分成多张二维码、重组拆分后的文件并验证。

         为了使用二维码传输文件,上一篇文章已经实现了获取信息存入二维码并打印。由于单个二维码存储的信息量是有限的,而且文件一般也比较大,所以必须把文件先进行拆分,拆分后一块一块信息存入多张二维码中,最后通过图像识别,把所有二维码信息准确读取后再重新组装成文件。接下来一步一步讨论如何用Python实现文件拆分、打印二维码、识别二维码、重组文件四个过程


目录

一、把文件拆分成块

二、把字节列表打印成多个二维码图片

三、利用OpenCV识别二维码图片并重组文件信息


一、把文件拆分成块

        首先读取文件,然后进行拆分。由于传输的文件格式多样,为了可以打开不同的文件格式,采用二进制方式读取文件是最通用的,通过以下Python代码可以实现文件的二进制读取,并一次文件读取所有内容。

        其中pic001.png是csdn图标的截图,如下图,大小为2.74KB。

        主要代码如下,mode='rb'设置了文件以二进制模式打开,read()方法一次性读取所有内容,若文件太大需要分段读取以免爆内存。

import os

# 使用二进制模式读取pic001.png图片
_file = open("pic001.png", mode="rb")
# 一次性读取所有字节(若文件太大请分段读取避免爆内存)
_contents = _file.read()

        接着是拆分文件,这里需要特别注意的是由于后续文件需要通过二维码传输,若直接使用原编码进行传输,编码不一定能使用明文查看,导致程序调试不方便,因此这里先把读取出来的文件数据转换成base64编码再进行拆分和传输,对base64有兴趣的可以阅读以下文章一篇文章彻底弄懂Base64编码原理https://blog.csdn.net/wo541075754/article/details/81734770

        主要代码如下,contents_base64=base64.b64encode(_contents),将_contents转换为base64编码,split_file()函数按固定长度拆分base64格式的字节流,其中_base64_str为字节流,_len为拆分的固定长度,最后返回拆分的字节列表_base64_str_list

import base64

# 转换为_base64格式方面传输数据
contents_base64 = base64.b64encode(_contents)
print("拆分前编码:"+contents_base64.decode('utf-8'))
# 调用拆分函数
_temp_list = split_file(contents_base64,128)

# 按固定长度拆分_base64格式的字节流,_base64_str为字节流,_len为拆分的固定长度
def split_file(_base64_str,_len):
    _base64_str_list = [_base64_str[i:i + _len] for i in range(0, len(_base64_str), _len)]
    return _base64_str_list

        输出结果如下,我们看到了熟悉的 AASUVORK5CYII=结尾的数据和列表。

拆分前编码:
iVBORw0KGgoAAAANSUhEUgAAAGkAAAApCAYAAAA22gdWAAAA(省略.....)gezoj6RGbYQAAAAASUVORK5CYII=
拆分后字节列表: [b'iVBORw0KGgoAAAANSUhEUgAAAGkAAAApCAYAAAA22gdWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAApNSURBVHhe7Znn',(省略.....)
b'xCG5mMOUJ++Psr+8SCQHKkx5wv4M+0uLRL7/J6Y8SX+uSfA/gezoj6RGbYQAAAAASUVORK5CYII=']

二、把字节列表打印成多个二维码图片

        文件拆分成字节列表后,下一步就是把每个列表的值存入二维码并打印了,这里直接用上一篇文章的打印二维码代码就可以了,代码如下。

import os
import qrcode

# 根据拆分后的字节流列表_base64_str_list,在cache文件夹下生成对应的二维码图片
def print_qr(_base64_str_list):
    # 删除原来cache文件夹内的文件
    for _pic_file in os.listdir("cache"):
        os.remove("cache/"+_pic_file)
    # 是否存在cache这个文件夹
    if not os.path.exists("cache"):
        os.makedirs("cache")
    # 循环生成二维码图片
    for i in range(0,len(_base64_str_list)):
        qr = qrcode.QRCode()
        qr.add_data(_base64_str_list[i], 0)
        img = qr.make_image()
        img.save("cache/split_file_00"+str(i)+".png")

        这里需要注意的是,每次生成二维码图片前需要先清空cache文件夹原有的内容,cache文件夹是专门用来存放生成的二维码图片的,如果不提前清空,可能会残留上一次生成二维码图片的数据,导致后续合成文件出错。删除文件夹内文件这里用到了os.listder("cache")函数,用于返回cache下的文件列表,然后使用os.remove("cache/"+_pic_file)删除文件夹下的文件。

        删除干净以后,循环调用qr.add_data()添加二维码信息,qr.make_image()img.save()保存二维码图片到cache文件夹下面。最后看到cache文件夹下面出现了29张二维码图片,命名规则为split_file_00x,如下图:

 三、利用OpenCV识别二维码图片并重组文件信息

        到目前为止文件已经拆分成29张二维码图片了,现在需要做的是重新识别二维码,并重组文件。这里利用OpenCV的库cv2和库pyzbar完成识别,代码如下。

import cv2
from pyzbar import pyzbar

# 识别拆分后二维码还原并验证
def verify_qr():
    _temp_str = ""
    for i in range(0, len(os.listdir("cache"))):
        # 读取二维码图片
        qrcode = cv2.imread("cache/split_file_00"+str(i)+".png")
        # 解析二维码中的数据
        data = pyzbar.decode(qrcode)
        # 在数据中解析出二维码的data信息
        _temp_str = _temp_str + data[0].data.decode('utf-8')
    return _temp_str

        这里需要注意的是 如果使用os.listder("cache")函数返回二维码文件列表,列表不一定按文件名顺序返回(还没搞懂),所以只能使"cache/split_file_00"+str(i)+".png"文件名自增循环一个一个读,避免读取顺序出错。读取结果如下:

拆分前编码:
iVBORw0KGgoAAAANSUhEUgAAAGkAAAApCAYAAAA22gdWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAkkJ
(省略......)
3OY8iR+a9OJxCG5mMOUJ++Psr+8SCQHKkx5wv4M+0uLRL7/J6Y8SX+uSfA/gezoj6RGbYQAAAAASUVORK5CYII=

还原后编码:
iVBORw0KGgoAAAANSUhEUgAAAGkAAAApCAYAAAA22gdWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAkkJ
(省略......)
3OY8iR+a9OJxCG5mMOUJ++Psr+8SCQHKkx5wv4M+0uLRL7/J6Y8SX+uSfA/gezoj6RGbYQAAAAASUVORK5CYII=

        可以看到,拆分前和识别还原后结果是一致的,证明文件信息已经正确重组了。以下是完整的代码。

import base64
import os
import cv2
from pyzbar import pyzbar
import qrcode


# 按固定长度拆分_base64格式的字节流,_base64_str为字节流,_len为拆分的固定长度
def split_file(_base64_str,_len):
    _base64_str_list = [_base64_str[i:i + _len] for i in range(0, len(_base64_str), _len)]
    return _base64_str_list


# 根据拆分后的字节流列表_base64_str_list,在cache文件夹下生成对应的二维码图片
def print_qr(_base64_str_list):
    # 删除原来cache文件夹内的文件
    for _pic_file in os.listdir("cache"):
        os.remove("cache/"+_pic_file)
    # 是否存在cache这个文件夹
    if not os.path.exists("cache"):
        os.makedirs("cache")
    # 循环生成二维码图片
    for i in range(0,len(_base64_str_list)):
        qr = qrcode.QRCode()
        qr.add_data(_base64_str_list[i], 0)
        img = qr.make_image()
        img.save("cache/split_file_00"+str(i)+".png")

# 识别拆分后二维码还原并验证
def verify_qr():
    _temp_str = ""
    for i in range(0, len(os.listdir("cache"))):
        # 读取二维码图片
        qrcode = cv2.imread("cache/split_file_00"+str(i)+".png")
        # 解析二维码中的数据
        data = pyzbar.decode(qrcode)
        # 在数据中解析出二维码的data信息
        _temp_str = _temp_str + data[0].data.decode('utf-8')
    return _temp_str


if __name__ == '__main__':
    # 使用二进制模式读取pic001.png图片
    _file = open("pic001.png", mode="rb")
    # 一次性读取所有字节(若文件太大请分段读取避免爆内存)
    _contents = _file.read()
    # 转换为_base64格式方面传输数据
    contents_base64 = base64.b64encode(_contents)
    print("拆分前编码:"+contents_base64.decode('utf-8'))
    # 调用拆分函数
    _temp_list = split_file(contents_base64,128)
    print("拆分后字节列表:",_temp_list)
    # 调用二维码生成函数
    print_qr(_temp_list)
    # 逐个识别所有生成的二维码,重新组合数据,验证是否正确
    print("还原后编码:"+verify_qr())

猜你喜欢

转载自blog.csdn.net/qq616491978/article/details/125471958