模拟生成新能源车辆数据

本文介绍了如何使用Python模拟生成包含车架号、行驶里程、车速等信息的新能源车辆数据,并将这些数据存储到HDFS中。模拟过程考虑了车速变化、电量变化、数据重复和混合前几天数据等因素。同时,文章提到了如何将数据写入本地文件系统,并提供了相关Python库如random和os的使用示例。
摘要由CSDN通过智能技术生成

概述

主要用yothon实现:模拟生成新能源车辆数据(当然,其他语言也是一样的,思路都差不多,只是语法稍有改变),主要用于测试一些代码或一些测试步骤(例如将数据上传到HDFS上等),当然对于像我这样的小白用来练手也是一个不错的选择。

基本要求:

  • 数据形式:

模拟生成当天的新能源车辆数据(字段信息必须包含:车架号、行驶总里程、车速、车辆状态、充电状态、剩余电量SOC、SOC低报警、数据生成时间等)

  • 要求:

1、最终部署时,将数据写入hdfs中(如果没有在虚拟机上部署Hadoop的话省略,将数据写入本地即可)
2、车辆数据要按天存储,数据格式是JSON格式,另外如果数据文件大于100M,则另起一个文件存。每天的数据总量不少于300M。比如假设程序是2023-01-1 运行,那么就将当前模拟生成的数据写入到HDFS的/can_data/2023-01-01文件夹的can-2023-01-01.json文件中,写满100M,则继续写到can-2023-01-01.json.2文件中,依次类推;
3、每天模拟生成的车辆数据中,必须至少包含20辆车的数据,即要含有20个车架号(一个车架号表示一辆车,用字符串表示);
4、每天生成的数据中要有少量(20条左右)重复数据(所有字段都相同的两条数据则认为是重复数据),且同一辆车的两条数据的数据生成时间间隔两秒;
5、每天生成的数据中要混有少量前几天的数据(即数据生成时间不是当天,而是前几天的)。

实现思路

可以从题中分析,其实整体的可以分为两大部分生成数据写入数据

1、生成数据

以下是我本人对数据生成的一些实现思路,其实模拟的并是很好,因为车辆在运行中时,车速是不可变化莫测的,想要很好的模拟车速还是比较困难。

假设: 只有车启动(或充电)时才会开始上传数据

  • 思路:

1、可以创建一个类,这个类接收一个车架号,用于生成一辆车一天的数据。

2、随机获取一个时间节点(use_car_time),作为本次用车(充电)的时间,就是相当于规定本次用车时长。

3、再随机获取一个时间节点,作为车辆启动的时间节点,从这个时间点开始每2秒生成一辆车的数据

4、随机初始化行程里程,行程里程随着车辆的运行而增加

5、随机初始化电量,电量随着车辆的变化而变化

6、确定当天的日期,让其在今天和前几天中选择,但被选中的几率极低,从而达到混入前几天的数据

7、初始化低电预警,当电量低于30%则提示:电量低于30%

以上部分我称为初始化车辆数据,在生成数据的逻辑中,至关重要。
以下是生成数据的逻辑:
生成数据逻辑

其实就是通过不断的判断车辆的状态,来生成对应的数据,逻辑其实并不复杂,但是需要梳理清楚
注意:数据要随着状态的变化而变化

1.1 rondom模块

生成随机数据主要通过Rondom模块来实现,以下会对rondom模块进行简单介绍,如果已经有过了解即可跳过。

random 模块是 Python 标准库中用于生成随机数的模块,它提供了众多的随机数生成函数。

下面是一些常用的 random 模块函数:

  1. random.random():返回一个 0 到 1 之间的随机浮点数。
  2. random.randint(a, b):返回一个 a 到 b 之间的随机整数。
  3. random.choice(seq):从序列 seq 中随机选择一个元素。
  4. random.choices(seq, weights=None, cum_weights=None, k=1):从序列seq中随机抽取元素的函数
  5. random.shuffle(x):将序列 x 随机打乱顺序,返回打乱后的序列。
  6. random.sample(population, k):从总体 population 中抽取 k 个不重复的元素出来,返回这 k 个元素构成的列表。

示例代码如下,演示了使用 random 模块生成随机数的基本用法:

import random

# 生成 0 到 1 之间的随机浮点数
print(random.random())

# 生成 1 到 10 之间的随机整数
print(random.randint(1, 10))

# 从列表中随机选择一个元素
items = ['apple', 'banana', 'orange']
print(random.choice(items))

# 打乱一个列表中的元素顺序
numbers = [1, 2, 3, 4, 5]
random.shuffle(numbers)
print(numbers)

# 从总体中随机抽取 3 个不重复的元素
population = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(random.sample(population, 3))

上述代码分别演示了生成随机浮点数、随机整数、随机选择列表元素、打乱列表元素顺序和随机抽样等基本用法。

重点讲一讲random.choices()

random.choices()

random.choices(seq, weights=None, cum_weights=None, k=1)random 模块中用于从序列中随机抽取元素的函数。其中,seq 表示需要抽取元素的序列,k 表示需要抽取的元素个数,可以通过调整 k 的值来实现有放回或无放回采样。

除了必选参数 seqk 之外,random.choices() 函数还提供了两个可选参数:

  • weights:表示每个元素对应的权重,默认情况下,所有元素的权重相等。
  • cum_weights:与 weights 参数一样,表示每个元素对应的累计权重。

如果提供了 weights 参数,则 random.choices() 函数会按照提供的权重值进行采样;如果提供了 cum_weights 参数,则 random.choices() 函数会按照提供的累计权重值进行采样。

下面的示例展示了使用 random.choices() 函数进行随机采样的基本用法:

import random

# 从字符串中随机抽取一个字符
s = "abcdefg"
print(random.choices(s))

# 从列表中随机抽取 3 个元素,每个元素的权重分别为 2、3、5
lst = ["A", "B", "C"]
w = [2, 3, 5]
print(random.choices(lst, weights=w, k=3))

上述代码分别演示了从字符串中随机抽取一个字符,以及从列表中随机抽取 3 个元素。在第二个示例中, weights 参数指定了每个元素的权重,即选 A 的概率为 2/10,选 B 的概率为 3/10,选 C 的概率为 5/10。最后输出的结果才按照这个概率来输出。

1.2模拟生成新能源车辆数据代码演示(python)

需要注意的是:输出的是一个二维列表,子列表表示一次用车所产生的数据
需要多少辆车的数据传入多少个车架号即可

import random
import datetime
import json

def get_vin(number: int) -> list:
    """
    用来生成指定数量的车架号

    param:number    生成多少量车的数据
    return: 返回一个列表
    """
    vin_set = set()  # 创建一个空集合
    for i in range(number):
        vin = ''.join(random.choices(
            '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', k=17))  # 车架号
        if vin not in vin_set:
            vin_set.add(vin)
    return list(vin_set)


class GenerationData:
    def __init__(self, vin):
        self.vin = vin

        self.mileage = round(random.uniform(200, 50000), 2)  # 行驶总里程
        # 随机初始化电量
        self.soc = round(random.uniform(10, 100), 2)  # 剩余电量SOC
        # 需要混入少量前几天的数据(让其在今天和前几天中选择,但被选中的几率极低)
        self.now_day = random.choices([(datetime.datetime.now() - datetime.timedelta(days=random.randint(1, 3))),
                                       datetime.datetime.now()], weights=[0.05, 0.95])[0]
        # 随机选取司机用车时间(或充电的时间)
        self.use_car_time = \
            random.choices([self.get_random_date(0, 23), self.get_random_date(8, 11), self.get_random_date(16, 22)],
                           weights=[0.2, 0.4, 0.4])[0]  # 模拟这个时间段用车的人较多
        # 低点预警
        self.soc_low_alarm = '电量正常' if self.soc >= 30 else '电量低于30%'
        # 用于保证数据为当天的数据
        self.time_compare = datetime.datetime.combine(self.now_day.date(), datetime.time(23, 59, 50))

    @staticmethod
    def get_random_speed():
        """
        用来随机获取车速
        """
        speed1 = random.randint(0, 60)
        speed2 = random.randint(61, 90)
        speed3 = random.randint(91, 120)
        speed = random.choices([speed1, speed2, speed3], weights=[0.6, 0.3, 0.1])[0]

        return speed

    def get_random_date(self, start: int, end: int):
        """
        用来生成当天的随机时间

        param:start 起始时间(小时)
        param:end   结束时间(小时)
        return:     当天的随机时间
        """

        # 生成随机的小时数、分钟数和秒数,并构造时间对象
        random_time = datetime.time(random.randint(
            start, end), random.randint(0, 59), random.randint(0, 59))

        # 构造完整的时间对象,包含日期和时间
        random_datetime = datetime.datetime.combine(self.now_day.date(), random_time)
        return random_datetime

    @staticmethod
    def get_travel_time():
        """
            随机获取一个随机时间(利用随机权重来设置)
        """
        random_hour_list = [0, 1, 2, random.randint(3, 5), random.randint(5, 8), random.randint(8, 10),
                            random.randint(10, 15), random.randint(15, 23)]
        random_hour = random.choices(random_hour_list, weights=[
            0.7, 0.3, 0.2, 0.15, 0.1, 0.05, 0.03, 0.01])[0]
        random_time = datetime.time(
            random_hour, random.randint(0, 59), random.randint(0, 59))
        return random_time

    def if_not_charge(self, choose_charge_or_not):
        data_list = []
        steer_time = self.get_travel_time()  # 随机获取一个驾驶时间
        print("司机本次开车", steer_time)
        seconds = (steer_time.hour * 60 + steer_time.minute) * 60 + steer_time.second  # 将驾驶时间转换为秒数
        flag = 0  # 立一个旗帜来判断是否达到驾驶时间
        print("司机的用车时间为:", self.use_car_time)

        while flag <= seconds:
            speed = self.get_random_speed()  # 随机生成0-130的车速,但侧重于0-60的车速
            if speed == 0:  # 模拟行驶中可能会停住
                status = '停车中'  # 设置车辆状态
                for i in range(random.randint(0, 50)):  # 模拟停车
                    self.use_car_time += datetime.timedelta(seconds=2)  # 每两秒更新一次时间
                    if self.use_car_time > self.time_compare:  # 保证生成的是今天的数据
                        break
                    data = {
                        '车架号': self.vin,
                        '行驶总里程': self.mileage,
                        '车速': speed,
                        '车辆状态': status,
                        '充电状态': choose_charge_or_not,
                        '剩余电量SOC': self.soc,
                        'SOC低报警': self.soc_low_alarm,
                        '数据生成时间': self.use_car_time.strftime('%Y-%m-%d %H:%M:%S')
                    }
                    data_list.append(data)
                    flag += 2
            else:
                status = '行驶中'
                # 假设每两秒随机跑10-60米
                run_mileage = random.uniform(0.01, 0.06)  # 因为速度是随机生成的,计算起来会不符合逻辑,那么这两秒跑了远也随机吧
                self.mileage += run_mileage  # 更新行驶里程
                consume = run_mileage * 0.1  # 消耗电量
                self.soc -= consume  # 更新剩余电量
                if self.soc <= 10:  # 电量小于10停止行驶
                    break
                self.soc_low_alarm = '电量正常' if self.soc > 30 else '电量低于30%'  # 低电提示
                # 加上时间差2秒
                self.use_car_time += datetime.timedelta(seconds=2)

                if self.use_car_time > self.time_compare:  # 保证生成的是今天的数据
                    break
                data = {
                    '车架号': self.vin,
                    '行驶总里程': self.mileage,
                    '车速': speed,
                    '车辆状态': status,
                    '充电状态': choose_charge_or_not,
                    '剩余电量SOC': self.soc,
                    'SOC低报警': self.soc_low_alarm,
                    '数据生成时间': self.use_car_time.strftime('%Y-%m-%d %H:%M:%S')
                }
                data_list.append(data)
                flag += 2
        print("本次用完车后的时间:", self.use_car_time)
        return data_list

    def if_charge(self, choose_charge_or_not):
        data_list = []
        status = '停车中'  # 默认停车中
        speed = 0  # 车速=0
        # 这时候就要考虑车主要充多电多久(随机生成充电时间)
        charge_timme = self.get_travel_time()
        print("司机本次充电时间", charge_timme)
        seconds = (charge_timme.hour * 60 + charge_timme.minute) * 60 + charge_timme.second  # 将充电时间转换为秒数
        flag = 0
        print("司机开始充电时间为:", self.use_car_time)
        print("未充电前电量为:", self.soc)
        if self.soc < 90:  # 如果此时车的电量是大于90的,那么就没有充电的必要了
            while flag <= seconds:
                if self.soc < 100:  # 确保电量不会超过100
                    self.soc_low_alarm = '电量正常' if self.soc > 30 else '电量低于30%'  # 低电提示
                    self.soc += 2 * (1 / 60)  # 充电效率跟充电桩有一定因素,暂不考虑太多,就假设1分钟充1%的电
                    self.use_car_time += datetime.timedelta(seconds=2)  # 每两秒更新一次时间
                    if self.use_car_time > self.time_compare:  # 保证生成的是今天的数据
                        break
                    data = {
                        '车架号': self.vin,
                        '行驶总里程': self.mileage,
                        '车速': speed,
                        '车辆状态': status,
                        '充电状态': choose_charge_or_not,
                        '剩余电量SOC': self.soc,
                        'SOC低报警': self.soc_low_alarm,
                        '数据生成时间': self.use_car_time.strftime('%Y-%m-%d %H:%M:%S')
                    }
                    data_list.append(data)
                    flag += 2
                else:
                    break
            print("司机结束充电时间为:", self.use_car_time)
            print("充电结束后电量为:", self.soc)
        return data_list

    def choose_whether_charge(self):
        charging = ['未充电', '充电中']
        if self.soc < 30:
            choose_charge_or_not = random.choices(charging, weights=[0.2, 0.8])[0]  # 如果电量小于30,则选择充电的就有80%的几率选择充电
        else:
            choose_charge_or_not = random.choices(charging, weights=[0.8, 0.2])[0]  # 反之就有80%选择不充电

        return choose_charge_or_not

    def generation_data(self):
        data_list = []
        # 选择是充电
        choose_charge_or_not = self.choose_whether_charge()

        while True:
            if self.use_car_time > self.time_compare:  # 保证生成的是今天的数据
                break
            if choose_charge_or_not == '未充电':
                list1 = self.if_not_charge(choose_charge_or_not)
                data_list.append(list1)  # 将列表合并
                # 退出循环即熄火,熄火之后又面临后续是否还需要用车
                # 有三种可能:在随机时间后用车,在随机时间后充电,今天不在用车
                if self.soc < 30:
                    weights = [0.1, 0.5, 0.4]
                else:
                    weights = [0.5, 0.1, 0.4]
                choose_may = random.choices(['随机时间后用车', '随机时间后充电', '今天不在用车'], weights=weights)[0]
                if choose_may == '随机时间后用车':  # 随机时间后用车,就将司机上次用完车后的时间+上随机时间
                    random_time = self.get_travel_time()
                    print(random_time, "后用车")
                    seconds = (random_time.hour * 60 + random_time.minute) * 60 + random_time.second
                    self.use_car_time += datetime.timedelta(seconds=seconds)  # 更新下次用车时间

                    continue  # 结束本次循环,等待下次用车
                elif choose_may == '随机时间后充电':
                    choose_charge_or_not = '充电中'  # 修改充电状态
                    random_time = random.randint(10, 500)
                    print(random_time, "后用充电")
                    self.use_car_time += datetime.timedelta(seconds=random_time)  # 更新下次用车时间
                    if self.use_car_time > self.time_compare:  # 保证生成的是今天的数据
                        break
                    continue  # 结束本次循环,等待下次用车
                else:
                    print("今天不再用车")
                    break
            else:  # 这种情况:车在充电
                list2 = self.if_charge(choose_charge_or_not)
                data_list.append(list2)  # 将列表合并
                # 充好电后,之后又面临后续是否还需要用车
                # 有两种可能:随机时间后用车,今天不在用车
                choose_may = random.choices(['随机时间后用车', '今天不在用车'], weights=[0.7, 0.3])[0]
                if choose_may == '随机时间后用车':  # 随机时间后用车,就将司机上次用完车后的时间+上随机时间
                    choose_charge_or_not = '未充电'  # 修改充电状态
                    random_time = self.get_travel_time()
                    print(random_time, "后用车")
                    seconds = (random_time.hour * 60 + random_time.minute) * 60 + random_time.second
                    self.use_car_time += datetime.timedelta(seconds=seconds)  # 更新下次用车时间
                    if self.use_car_time > self.time_compare:  # 保证生成的是今天的数据
                        break
                    continue  # 结束本次循环,等待下次用车
                else:
                    print("今天不在用车")
                    break
        return data_list


if __name__ == '__main__':
    vins_list = get_vin(1)  # 生成50辆车的数据
    vin1 = vins_list.pop()  # 随机取出一辆,先模拟一辆车
    gd = GenerationData(vin1)	# 创建对象
    # 生成数据
    data_li = gd.generation_data()
    print(len(data_li))

2、将生成的数据存储到hdfs

无论存储到本地还是存储到hdfs,基本思路其实都是差不多的。小编这里两个都会演示。

  • 首先要部署到hdfs上的话,需要在虚拟机上部署Hadoop,如果没有部署,可以直接跳过了,可以试试将数据存储到本地,基本思路都差不多,但需要用到os库。
  • 如果对hdfs库中InsecureClient模块不熟悉的,可以看看我的主页,会有一期讲解InsecureClient模块的使用,主要介绍python模块对hdfs的增删改查等一系列简单操作
  • 本例中会用到

2.1连接上web端的hdfs

  1. 下载 hdfs 库

pip install hdfs

  1. 导入模块

from hdfs import InsecureClient

InsecureClient是hdfs模块中提供的一种客户端对象,它可以通过安全和非安全两种方式连接到HDFS集群。

  1. 创建连接

client = InsecureClient(‘http://192.168.88.129:50070’, user=‘root’)

在本例中,我们使用的是非安全方式连接HDFS,因此使用了InsecureClient作为客户端对象

  • 第一个参数:'http://192.168.88.129:50070’是HDFS服务的访问地址。在Hadoop集群中,HDFS服务一般运行在一个或多个节点上,通过这个地址可以访问HDFS服务提供的Web UI界面。
  • user:用于指定客户端的用户名,这个用户名需要在HDFS中有相应的权限。

2.2 代码中会用到的InsecureClient模块中的方法

一个简单的表格是这么创建的:

方法作用
makedirs用于创建指定路径的目录,可以同时设置目录的权限如果指定的路径已经存在,则会抛出HdfsError异常。
status获取文件或目录的详细信息(本例中会用来判断文件是否存在)
content列出指定路径的文件或目录的详细内容信息(本例中会用来查看文件的大小)
write将数据写入到指定的 HDFS 文件路径

2.3 参数介绍

makedirs()基本参数

client.makedirs函数的参数包括:

  • hdfs_path: 要创建的HDFS路径。必选参数。
  • permission: 创建目录时指定的权限。默认值为None,表示使用默认的权限。如果设置了权限,则必须是一个八进制数字符串,例如"755"表示创建的目录权限为rwxr-xr-x

例如,要创建/test目录,并设置其权限为755,可以使用以下代码:

from hdfs import InsecureClient

client = InsecureClient('http://192.168.88.129:50070', user='root')

# 创建/test目录,权限设置为755
client.makedirs('/test', permission=755)

​ 在上述代码中,client.makedirs函数指定了要创建/test目录,并设置目录的权限为755。如果不指定权限,默认使用HDFS的默认权限。

​ 需要注意的是,如果指定的路径已经存在,则会抛出HdfsError异常。在使用client.makedirs函数前,需要确保指定的路径不存在,并且参数的设置符合预期。

status()基本参数:

client.status函数的基本参数如下:

  • hdfs_path: 需要获取信息的文件或目录路径。必选参数。
  • strict: 是否开启严格模式。默认为True。如果开启严格模式,当路径不存在时会抛出HdfsError异常。如果关闭严格模式,路径不存在时会返回一个空的dict对象。

在实际使用中,我们一般只需要指定hdfs_path参数,获取文件或目录的详细信息即可。需要注意的是,client.status函数返回的是一个dict对象,其中包含了文件或目录的详细信息。可以通过取字典中的某个键的方式,获取对应的值。例如:

from hdfs import InsecureClient
client = InsecureClient('http://192.168.88.129:50070', user='root')

# 文件路径
hdfs_path = '/car_data/2023-05-29/car-2023-05-29.json'

file_info = client.status(hdfs_path
print(file_info['length'])  # 打印文件的大小
content()基本参数

client.content函数的参数包括:

  • hdfs_path: 要列出的HDFS路径。必选参数。
  • strict: 是否开启严格模式,当开启严格模式时,如果目录或文件不存在,将抛出HdfsError异常。默认值为False

例如,要列出根目录/的内容信息,开启严格模式,可以使用以下代码:

from hdfs import InsecureClient
client = InsecureClient('http://192.168.88.129:50070', user='root')

# 文件路径
hdfs_path = '/'

content_info = client.content(hdfs_path=hdfs_path, strict=True)
print(content_info)

​ 在上述代码中,client.content函数指定了要列出/目录的内容信息,并且设置了strict=True,表示开启严格模式,如果目录不存在将抛出异常。最后,将目录的内容信息打印出来。

​ 需要注意的是,如果指定的路径不存在,且未开启严格模式,将返回None。如果开启了严格模式,则在指定的路径不存在时会抛出异常。在使用client.content函数前,需要确保指定的路径存在,并且参数的设置符合预期。

write()常用参数介绍:
  1. path(必选):表示 HDFS 文件系统的文件路径,如果包含文件名,则需要在文件名前添加目录名,例如 ‘/dir/filename’ 表示将数据写入到 HDFS 文件系统中的 ‘/dir’ 目录下的 ‘filename’ 文件中;
  2. data(必选):表示要写入文件的数据,必须是 bytes 类型;
  3. overwrite(可选):表示是否覆盖已经存在的文件,默认为 False,即不覆盖;
  4. append(可选):表示是否将数据追加到已经存在的文件中,默认为 False,即不追加;
  5. blocksize(可选):表示要写入的数据块的大小,默认为 None(自动调整块大小);
  6. replication(可选):表示写入数据时使用的文件副本数,默认为 None。

示例代码如下,假设要将数据写入到 hdfs://namenode:8020/dir/filename 文件中:

from hdfs import InsecureClient

# 创建连接到 HDFS 的客户端实例
client = InsecureClient('http://namenode:50070')

# 要写入的数据
data = b'Hello, world!'

# 向 HDFS 写入数据
with client.write('/dir/filename', overwrite=True) as writer:
    writer.write(data)

上述代码中,首先创建了一个连接到 HDFS 的客户端实例,然后准备要写入的数据。接下来使用 client.write() 方法向指定路径 ‘/dir/filename’ 的文件中写入数据,同时开启了覆盖已有文件的选项。由于代码中使用了 with 语句块,write() 方法会返回一个文件写入器(file writer)对象 writer,然后在语句块中向该对象中写入数据,最后退出语句块时,该对象会自动关闭,提交数据块到 HDFS。写入的数据即为 b’Hello, world!'。

2.4、实现思路

明确目的:

  1. 一边生成数据一边写入数据
  2. 每次写入5条数据,并判断文件大小是否超出阈值(100M 相当于 100 * 1024 * 1024)的测试的时候改小一点
  3. 写入的同时,随机添加一些重复数据,来实现题目要求
  4. 每当超出阈值创建新的文件写入

实现的基本步骤:
实现的基本步骤

2.5 将数据写入hdfs代码实现(python)

from hdfs import InsecureClient
from generation_data import GenerationData
import random
import json
import datetime


def get_vin(number: int) -> list:
    """
    用来生成指定数量的车架号

    :param:number    生成多少量车的数据
    :return: 返回一个列表
    """
    vin_set = set()  # 创建一个空集合
    for i in range(number):
        vins = ''.join(random.choices(
            '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', k=17))  # 车架号
        if vins not in vin_set:
            vin_set.add(vins)
    return list(vin_set)


def create_folder_if_not_exists(file_path):
    """
        判断文件是否存在,不存在则创建
    :param file_path:文件位置
    :return:
    """
    if client.status(file_path, strict=False) is None:
        client.makedirs(file_path, permission=755)  # 创建目录并将数据修改权限为755
        print(f"目录{file_path}创建成功!")
    else:
        print("目录已存在")


def add_repeating_data(data_list: list):
    """
    用于向列表中添加重复数据
    随机添加5-15条不等
    列表内的数据需要是字典
    :param data_list: 需要添加重复数据的列表
    :return:无返回值,对传进来的数据进行隐形操作
    """
    # sample()函数从0到列表总长度之间随机选择random.randint(20,100)整数作为重复的数据下标
    try:
        repeat_indices = random.sample(range(len(data_list)), random.randint(5, 15))
        print(repeat_indices)
        for i in repeat_indices:
            # 返回字典中所有键值对的元素,以便同时访问字典中所有键和它们对应的值
            repeat_data = {k: v for k, v in data_list[i].items()}
            print(data_list[i], "下面添加了:", repeat_data)
            data_list.insert(i + 1, repeat_data)  # 将数据插入原数据的下一行
    except Exception as e:
        print("添加失败:", e)


def split_data(one_vin_data, null_list: list) -> list:
    """
    并随机添加行程重复数据
    拆分传入的列表数据,将列表数据拆分为,5个数据为一个子列表
    :param:one_vin_data:一辆车架号的列表数据
    :param:null_list:一个空列表
    :return: 二维列表(每个列表5个数据)
    """
    n = 5  # 每个子列表包含10个元素
    for tmp_list in one_vin_data:
        """
        随机选择本次行程是否会出现重复数据,出现:添加5-20条数据
        用于选择是否出现重复数据,出现的概率为3%
        出现返回True
        不出现返回False
        """
        flag = random.choices([True, False], weights=[0.03, 0.97])[0]
        if flag:  # 出现:添加5-15条数据
            add_repeating_data(tmp_list)

        # 将数据拆分为10个数据为一个小列表
        for i in range(0, len(tmp_list), n):
            null_list.append(tmp_list[i:i + n])
    return null_list


if __name__ == '__main__':
    client = InsecureClient('http://192.168.88.129:50070', user='root')
    NOW_DATA_STR = datetime.datetime.now().date().strftime('%Y-%m-%d')  # 当天日期
    FILE_PATH = f'/car_data/{NOW_DATA_STR}'  # 需要的目录
    # threshold = 100 * 1024 * 1024  # 文件大小阈值为100MB
    threshold = 100000  # 设置文件阈值
    index = 2  # 文件后缀

    # 创建文件夹
    create_folder_if_not_exists(FILE_PATH)

    data_path = FILE_PATH + f'/car-{NOW_DATA_STR}.json'  # 初始化文件地址

    # 生成车架号
    vin = get_vin(1)

    # 循环写入数据 -> 5条数据5条数据的写
    for i in range(len(vin)):
        tmp_list = []  # 用一个临时列表来临时存储数据
        # 生成数据
        gd = GenerationData(vin[i])
        one_vin_data_list = gd.generation_data()  # 生成一辆车的数据
        # 随机添加重复数据,并切割数据列表,所有的子列表中有5个数据
        data_list = split_data(one_vin_data_list, tmp_list)  # -> 二维列表
        # 循环子列表
        for son_list in data_list:  # 一个列表一个列表的写入
            # 判断文件是否存在,不存在则返回None
            if client.status(data_path, strict=False):
                # 文件存在,追加内容
                with client.write(data_path, append=True, encoding='utf-8') as writer:
                    # client.set_permission(data_path, permission='777')  # 修改文件权限
                    for data in son_list:
                        # 转为json数据
                        data = json.dumps(data, ensure_ascii=False)
                        # 将编码后的字符串写入文件中,并添加换行符
                        writer.write(data + '\n')
                        writer.flush()  # 立即将缓存的数据全部写入文件
                    file_info = client.content(data_path)  # 获取文件信息
                    file_size = file_info['length']  # 获取文件大小
                    # print(file_size)
                    if file_size > threshold:  # 如果文件大于阈值则更新文件地址
                        data_path = FILE_PATH + f'/car-{NOW_DATA_STR}.json.{index}'
                        index += 1
            else:  # 不存在则开一个新的文件
                with client.write(data_path, encoding='utf-8') as writer:
                    for data in son_list:
                        # 转为json数据
                        data = json.dumps(data, ensure_ascii=False)
                        # 将编码后的字符串写入文件中,并添加换行符
                        writer.write(data + '\n')
                        writer.flush()  # 立即将缓存的数据全部写入文件

3、将数据写入本地

基本思路的实现思路与写入hdfs差不多。所以就不在多说。
需要用到os库

3.1 简单介绍os库

os 模块是 Python 语言中一个常用的操作系统相关库,通过该模块可以完成许多涉及文件、目录、进程等的操作。
主要的功能包括:

  • 操作文件和目录:如创建、重命名、删除、移动、复制等文件和目录操作;
  • 进程管理:如获取进程 ID、杀死进程、调用新进程等操作;
  • 系统信息:如获取系统版本、CPU 数量、内存使用情况等信息;
  • 文件描述符操作:如打开、关闭文件,读取、写入数据等操作;
  • 环境变量操作:如获取、设置、删除环境变量。

os 模块中的函数、方法和常量很多,主要包括以下几个常用的部分:

  • 文件和目录操作相关函数:os.getcwd(),os.listdir(),os.mkdir(), os.rmdir(),os.path.join(),os.path.dirname(),os.path.basename() 等;
  • 进程管理相关函数:os.fork(),os.kill(),os.wait() 等;
  • 系统信息相关函数:os.name,os.environ 等;
  • 文件描述符操作函数:os.open(),os.close(),os.read(),os.write() 等。

3.2 本次案例会用的到方法

方法作用
os.mkdir()在指定的路径中创建新的目录。
os.makedirs()递归创建多层目录
os.path.exists()os.path 模块中的函数,其作用是用于判断指定的路径是否存在,如果路径存在则返回 True,否则返回 False
os.path.getsize()用于获取指定文件的大小,单位为字节

3.3 基本参数

os.mkdir() 函数的主要参数如下:
  • path:必选,表示要创建的目录路径。这是一个字符串,可以包含多级文件夹,例如 "C:\\data\\temp\\images",其中路径分隔符可以使用 “” 或 “/”。
  • mode:可选,表示新目录的权限。默认值为 0o777,一般不需要指定,除非你需要创建一个权限不同的目录。在 Unix/Linux 中, mode 表示新建目录的文件权限掩码(umask);在 Windows 中,忽略 mode 参数,使用操作系统的默认权限。

当运行 os.mkdir 函数时,程序会尝试在指定路径下创建新目录,如果该目录不存在,则会创建成功,并返回 None;如果该目录已经存在,则会抛出 OSError 异常,并提示目录已经存在。

示例代码如下,用于在当前工作目录下创建一个名为 “example” 的新目录:

import os

# 创建一个新目录
os.mkdir('example')

上述代码实现了在当前工作目录下创建名为 “example” 的新目录。

os.makedirs() 函数的主要参数如下:
  • name:必选,表示要创建的目录路径,可以是一个字符串类型的路径,也可以是一个包含多个路径的列表类型。
  • mode:可选,表示新目录的权限,默认值为 0o777。
  • exist_ok:可选,表示如果目录已经存在时是否抛出异常,默认为 False,即目录已存在时会抛出异常,设为 True 时,不会抛出异常。

当运行 os.makedirs() 函数时,程序会尝试在指定路径下递归创建所有目录层次。如果路径对应的目录已经存在,则不会抛出异常。如果路径中的某个目录不存在,则会创建该目录,直到创建所有目录为止。

示例代码如下,使用 os.makedirs() 在当前目录下递归创建多层目录:

import os

# 递归创建目录
os.makedirs('./data/input', exist_ok=True)

上述代码实现了在当前目录下递归创建了 ./data/input 两层目录。

os.path.exists()参数:

参数 path 表示需要检查是否存在的路径。该函数会在执行时检查指定的路径是否存在,如果路径存在则返回 True,否则返回 False

示例代码如下,用于检查指定路径是否存在:

import os

# 判断指定路径是否存在
if os.path.exists('./data/input'):
    print('指定路径存在')
else:
    print('指定路径不存在')

上述代码会先判断 ./data/input 目录是否存在,如果存在,则输出 "指定路径存在",否则输出 "指定路径不存在"

os.path.exists() 函数没有任何可选参数,只有一个必选参数 path,表示需要检查的路径。

os.path.getsize() 函数的语法:
os.path.getsize(path)

其中,参数 path 表示需要获取大小的文件路径。该函数会在执行时获取指定文件的大小,并以字节的形式返回文件的大小。

示例代码如下,用于获取指定文件的大小:

import os

# 获取文件大小
size = os.path.getsize('./data/example.txt')
print('文件大小为', size, '字节')

上述代码会获取 ./data/example.txt 文件的大小,并输出文件大小,单位为字节。

需要注意的是,os.path.getsize() 函数只能获取文件的大小,如果传入的参数是目录路径,则会抛出 OSError 异常。

总结

写入本地就不做代码演示了,只要明确思路,其实还是写起来也并不困难。可以用with open(name,mode,encoding) as f:来做,其中name:是打开的文件名的字符串(可以包含文件所在的具体路径),mode:设置打开文件的模式(访问模式):只读、写入、追加等,encoding:编码格式(推荐使用UTF-8)。

本次案例对于小白来说是一个非常不错的练手案例,其实代码和逻辑并不复杂,但是需要一定的耐心,如果对你有用的话给小编点个赞把~~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值