首页 > 编程语言 >Python工具箱系列(三十八)

Python工具箱系列(三十八)

时间:2023-07-13 11:25:43浏览次数:32  
标签:字节 三十八 area Python self pm25 import 工具箱 def

二进制文件操作(下)

上文介绍将类的属性值保存到二进制文件的基本操作。在实际中,还有可能保存文本信息。例如,传感器可能还会有自己所在区域的信息。此时,对于二进制文件的读写提出了挑战。如何才能够在读取时,知道所读的字节是整数、浮点数而不是字符呢?解决的方法有:
◆全程避免引入字符串,而使用相对应的代码来表示。例如数字1代表东部区域,数字2代表西部区域,数据产生时只发代码,从而避免相关问题。
◆字符串定长。例如固定为15个字节长,但这样可扩展性差。
◆字符串变长,此时最容易导致解码失败。通常会在字符串前再加上字符串长度的一个记录值,从而方便后续解码。

下面的版本2的示例代码演示了这一处理过程:

 

import binascii
from encodings.utf_8 import decode
import random
import struct
from datetime import datetime
from io import BytesIO
from time import sleep

import arrow


class sensordata_v2():
    def __init__(self):
        utc = arrow.utcnow()
        self._timestamp = utc.to('Asia/Shanghai')

    @property
    def counter(self) -> int:
        """
        计数器

        Returns:
            int: 从0开始的计数器
        """
        return self._counter

    @counter.setter
    def counter(self, value: int):
        self._counter = value

    @property
    def pm25(self) -> float:
        """
        PM25测量值

        Returns:
            float: pm25的当前测量值
        """
        return self._pm25

    @pm25.setter
    def pm25(self, value: float):
        self._pm25 = value

    @property
    def timestamp(self) -> datetime:
        """
        当前时点

        Returns:
            datetime: 当前的时间
        """
        return self._timestamp.datetime

    @property
    def area(self) -> str:
        """
        所在区域

        Returns:
            str: 区域名称
        """
        return self._area

    @area.setter
    def area(self, value: str):
        self._area = value

    def __str__(self):
        """
        以文字输出相关内容

        Returns:
            string: 说明性文字
        """
        return f"counter: {self.counter}, pm25: {self.pm25}, area: {self.area}, timestamp: {self.timestamp}"

    def __repr__(self):
        """
        输出字节流的16进制内容

        Returns:
            string: 16进制显示相关数值
        """
        return str(binascii.hexlify(self.toBytes()))

    def toBytes(self):
        """
        将相关数据转换成为bytes,便于网络传输或者写入文件

        Returns:
            bytes: 整合测量数据到字节流中
        """
        with BytesIO() as byio:
            # 变长字符串,先生成bytes,再计算长度。
            info = self.area.encode('utf-8')
            infolen = len(info)

            # 字节流总长度的计算
            framelen = 4 + 8 + 4 + infolen + 8
            # 将字节长度写入
            byio.write(struct.pack('<i', framelen))

            # 写入其它非字符串属性值
            byio.write(struct.pack('<i', self.counter))
            byio.write(struct.pack('<d', self.pm25))

            # 将字符串长度先写入
            byio.write(struct.pack('<i', infolen))

            # 再将转换好的字节流写入
            byio.write(info)
            byio.write(struct.pack('<d', self._timestamp.timestamp()))
            return byio.getvalue()

    def fromBytes(self, data):
        """
        从字节流中解出相关值

        Args:
            data (bytes): 待解析的字节流
        """
        self.counter, self.pm25, strlen = struct.unpack('<idi', data[:16])
        areainfo = data[16:16+strlen]
        self.area = areainfo.decode()
        st = struct.unpack('<d', data[16+strlen:])
        self._timestamp = arrow.get(st[0])


def toFile(filename):
    """
    向二进制文件中写入数据

    Args:
        filename (string): 文件名称
    """
    arealist = ['east', 'south', 'west', 'north', 'center']
    with open(filename, 'wb') as myfile:
        for index in range(10):
            sensor_obj = sensordata_v2()
            sensor_obj.counter = index
            sensor_obj.pm25 = random.uniform(0, 300)
            sensor_obj.area = random.choice(arealist)
            data = sensor_obj.toBytes()
            myfile.write(data)
            sleep(1)


def fromFile(filename):
    """
    从二进制文件中获得保存的信息,并且重建对象

    Args:
        filename (string): 文件名称
    """
    with open(filename, 'rb') as myfile:
        for index in range(10):
            # 找到本记录的大小
            framelenbytes = myfile.read(4)
            framelen = int.from_bytes(
                framelenbytes, byteorder='little', signed=False)
            print("framelen=", framelen)
            # 再读出后续的数据
            framebytes = myfile.read(framelen)
            sensor_obj = sensordata_v2()
            sensor_obj.fromBytes(framebytes)
            print(sensor_obj)


datafilename = r"d:\dev\sensor.dat"
toFile(datafilename)
fromFile(datafilename)

 

版本1与版本2的区别就在于如何处理类中的字符串。由于字符串的长度不一,为了后续解析的方便,在记录时保存了2个记录。

1、framelen-记录当前sensordata_v2实例输出字节流的长度,但不包括自己的长度(自身占据4个字节)。

2、infolen-记录area属性输出时的长度。由于'east/west/north/south/center'长度从4到6不同,为了保证后续能够正确的解出字符串,同时考虑read操作时最后一次读过,不使用seek进行复杂的跳转计算,必须将infolen在字符串前进行保存。

在fromFile函数中根据framelen读出对应的字节流。随后在fromBytes中先解出infolen,再从字节流中取出长度为infolen的字节流,拆包形成area字符串。随后再解出timestamp。以上过程形成了一个反复拆解的过程,并且读取时文件指针不跳转,相对简洁有效。

 

标签:字节,三十八,area,Python,self,pm25,import,工具箱,def
From: https://www.cnblogs.com/shanxihualu/p/17549858.html

相关文章

  • PYTHON随笔-打印错误堆栈
    PYTHON随笔-打印错误堆栈importsysimporttracebackdefprint_traceback():'打印通常的回溯信息,且附有每帧中的局部变量的列表'tb=sys.exc_info()[2]#返回当前异常的(type,value,traceback)whiletb.tb_next:tb=tb.tb_next#栈中的下一个trac......
  • python 数据类型 字符串
    目录python数据类型字符串Python字符串定义Python字符串连接Python转义字符Python字符串运算符Python字符串格式化Unicode字符串python的字符串内置函数python数据类型字符串Python字符串定义#字符串是Python中最常用的数据类型。我们可以使用引号('或")来创建字......
  • 解决指定GPU运行和训练 python程序 、深度学习单卡、多卡 训练GPU设置【一文读懂】的
    指定GPU运行和训练Python程序,深度学习单卡、多卡训练GPU设置在进行深度学习任务时,GPU的使用是提高训练速度和效果的重要手段之一。在Python中,我们可以通过一些方法来指定GPU的运行和训练。指定GPU运行当我们使用多个GPU进行训练时,有时需要手动指定程序运行在哪个GPU上。这可以......
  • 解决支持vscode 1.62 的python插件版本的具体操作步骤
    如何实现支持VSCode1.62的Python插件版本作为一名经验丰富的开发者,我将指导你如何实现支持VSCode1.62的Python插件版本。下面是实现这个目标的步骤:步骤操作1安装VSCode最新版本2创建一个Python插件3更新插件依赖和Python版本4更新插件功能以适应VSCode1......
  • 折线图怎么设置横坐标表示年份python 来解决一个具体问题的方案
    折线图怎么设置横坐标表示年份在使用Python绘制折线图时,可以通过设置横坐标来表示年份。本文将介绍如何根据年份绘制折线图,并给出一个具体的问题来解决。问题描述假设我们有一份数据,记录了某城市从2010年到2020年每年的降水量。我们想要使用折线图来展示这些数据,横坐标表示年份,......
  • 怎么用python抢大麦网演唱会门票 这个问题怎么解决?
    使用Python抢大麦网演唱会门票引言随着互联网的发展,越来越多的人选择在线购买演唱会门票。然而,由于演唱会门票数量有限,很多时候门票在开售后仅仅几分钟内就被抢购一空,这给想要购票的人们带来了很大的困扰。本篇文章将介绍如何使用Python来抢购大麦网演唱会门票,解决这个实际问题。......
  • 怎么升级anconda的python版本 来解决一个具体问题的方案
    如何升级Anaconda的Python版本Anaconda是一个使用Python进行数据科学和机器学习的强大工具。它提供了一个简单的方式来安装和管理Python环境,包括Python解释器、各种常用的科学计算库和工具。然而,有时候我们需要升级Anaconda的Python版本,以便使用最新的功能和库。下面是一些简单的......
  • 怎么让vim执行python在conda中 来解决一个具体问题的方案
    怎么让vim执行python在conda中问题描述在使用vim编辑器进行Python编程时,我们可能会遇到使用conda环境时无法直接执行python代码的问题。这是因为vim默认使用系统的Python环境,而不是我们使用conda创建的环境。因此,我们需要找到一种方法来让vim能够在我们指定的conda环境中执行Pyth......
  • 怎么去除列表中的空格Python 这个问题怎么解决?
    如何去除列表中的空格-Python在Python编程中,我们经常需要处理列表。有时候,我们可能会遇到列表中包含空格的情况。这些空格可能是由于用户输入或者其他原因造成的。如果不处理这些空格,可能会导致程序出现错误或者输出结果不符合预期。本文将介绍如何去除Python列表中的空格,以解......
  • Python基础数据之列表
    (Python基础数据之列表)一、列表介绍1.简介列表是Python中最基本的数据结构,列表是最常用的Python数据类型,列表是一个数据的集合,集合内可以放任何数据类型,可对集合方便的增删改查操作。Python已经内置确定序列的长度以及确定最大和最小的元素的方法。2.列表的特性①可以和字符......