zoukankan      html  css  js  c++  java
  • 树莓派ZeroW的Python中使用SQLite数据库

    >> [目录] 数据远程采集 Step by Step


    SQLite数据库(www.sqlite.org)是一个轻型的数据库引擎,应用非常广泛。我们使用SQLite来存储采集到的通讯数据,一帧通讯原始数据加上时间戳后作为一条记录存入数据库中。在这个项目中,只需要用到数据库的存储功能,不需要查询之类的(到本地上位机上解析数据时才会用到),所以下面也只介绍存储相关的部分,其他功能可以参考这个网址:

    https://www.runoob.com/sqlite/sqlite-python.html


    程序说明


    用下面这些函数就可以插入记录完成存储,还需要解决的是SQL语句:sql_create_table、sql_insert_record,以及记录集合:records_list。

      1 import sqlite3
      2 
      3 # 连接到SQLite数据库:DB_NAME,如果不存在就创建
      4 conn = sqlite3.connect(DB_NAME)
      5 # 创建一个游标Cursor,可以通过Cursor来执行SQL语句
      6 cursor = conn.cursor()
      7 # 创建记录表:records
      8 cursor.execute(sql_create_table)
      9 # 插入多条记录
     10 cursor.executemany(sql_insert_record, records_list)
     11 # 关闭Cursor
     12 cursor.close()
     13 # 提交事务
     14 conn.commit()
     15 # 关闭数据库连接
     16 conn.close()


    >> SQL语句:sql_create_table、sql_insert_record

    sql_create_table

    在数据库中建一个表records,表中记录的结构为:单条记录结构:id(自增),时间戳(text),从数据库创建开始的累计时间(real),通讯原始数据(400个,int)

    sql_insert_record

    插入记录时只需要:时间戳、累计时间、通讯数据*400

      1 def init_sql_sentences(param_num):
      2   global sql_create_table
      3   global sql_insert_record
      4 
      5   # sql_create_table
      6   sql_create_table = 'create table if not exists records('
      7   sql_create_table += 'id integer primary key autoincrement, '
      8   sql_create_table += 'datetime text, '
      9   sql_create_table += 'runningtime real, '
     10   for i in range(0, param_num - 1):
     11     sql_create_table += 'param' + str(i) + ' int, '
     12   sql_create_table += 'param' + str(param_num - 1) + ' int)'
     13 
     14   # sql_insert_record
     15   sql_insert_record = 'insert into records values (null, ?, ?, '
     16   for i in range(0, param_num - 1):
     17     sql_insert_record += '?, '
     18   sql_insert_record += '?)'


    >> 记录集合:records_list

    按照记录的格式,将时间戳、通讯数据等存入单条记录record_buff[],然后再把record_buff[]添加到到记录集records_list[],这里使用了tuple,把record_buff[]转换成元组,这样就负荷cursor.executemany()函数要求的格式了。

      1 records_list = []
      2 record_buff = []
      3 record_buff.append('')
      4 record_buff.append(0.0)
      5 for i in range(0, DB_PARAMS_LENGTH):
      6   record_buff.append(0)
      7 
      8 ####
      9 record_buff[0] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
     10 record_buff[1] = round((time.time() - start_time), 1)
     11 for i in range(0, DB_PARAMS_LENGTH):
     12   record_buff[i + 2] = comn_data[i]
     13   comn_data[i] = 0
     14 records_list.append(tuple(record_buff[:]))


    创建测试文件test_sqlite.py

    用模拟通讯数据,生成100条记录,插入数据库,等待0.4s。循环10次以后退出。

    pi@raspberrypi:~ $ sudo nano test_sqlite.py

      1 # -*- coding:utf-8 -*-
      2 import time
      3 import sqlite3
      4 import os
      5 from datetime import datetime
      6 
      7 DEFAULT_DIR         = '/home/pi/project/'
      8 DB_DIR              = '/home/pi/project/data/'
      9 DB_TMP_DIR          = '/home/pi/project/data/tmp/'
     10 DB_UPDATING_DIR     = '/home/pi/project/data/updating/'
     11 DB_UPDATED_DIR      = '/home/pi/project/data/updated/'
     12 
     13 DB_NAME             = ''
     14 
     15 PRODUCT_TYPE        = 'NULL'
     16 DEVICE_ID           = 999
     17 DB_PARAMS_LENGTH    = 400
     18 
     19 sql_create_table    = ''
     20 sql_insert_record   = ''
     21 
     22 def init_sql_sentences(param_num):
     23   ####
     24 
     25 def main():
     26   global PRODUCT_TYPE
     27   global DEVICE_ID
     28   global DB_PARAMS_LENGTH
     29 
     30   record_count = 0
     31   insert_count = 0
     32 
     33   record_buff = []
     34   records_list = []
     35   comn_data = [0 for i in range(DB_PARAMS_LENGTH)]
     36 
     37   record_buff.append('')
     38   record_buff.append(0.0)
     39   for i in range(0, DB_PARAMS_LENGTH):
     40     record_buff.append(0)
     41 
     42   if not os.path.exists(DEFAULT_DIR):
     43     os.mkdir(DEFAULT_DIR)
     44   if not os.path.exists(DB_DIR):
     45     os.mkdir(DB_DIR)
     46   if not os.path.exists(DB_TMP_DIR):
     47     os.mkdir(DB_TMP_DIR)
     48   if not os.path.exists(DB_UPDATING_DIR):
     49     os.mkdir(DB_UPDATING_DIR)
     50   if not os.path.exists(DB_UPDATED_DIR):
     51     os.mkdir(DB_UPDATED_DIR)
     52 
     53   init_sql_sentences(DB_PARAMS_LENGTH)
     54 
     55   DB_NAME = DB_TMP_DIR+PRODUCT_TYPE + '_' + str(DEVICE_ID).rjust(3,'0') + '_' 
     56             + time.strftime('%Y-%m-%d_%H%M%S', time.localtime()) + '.db3'
     57 
     58   print('>> sqlite test start...')
     59   print(DB_NAME)
     60 
     61   start_time = time.time()
     62   while insert_count < 10:
     63     # set fake data
     64     for i in range(0, DB_PARAMS_LENGTH):
     65       comn_data[i] = i
     66     comn_data[0] = record_count
     67 
     68     record_buff[0] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
     69     record_buff[1] = round((time.time() - start_time), 1)
     70     for i in range(0, DB_PARAMS_LENGTH):
     71       record_buff[i + 2] = comn_data[i]
     72       comn_data[i] = 0
     73 
     74     records_list.append(tuple(record_buff[:]))
     75     record_count = record_count + 1
     76 
     77     if((record_count % 100) == 0):
     78       conn = sqlite3.connect(DB_NAME)
     79       cursor = conn.cursor()
     80       cursor.execute(sql_create_table)
     81       cursor.executemany(sql_insert_record, records_list)
     82       cursor.close()
     83       conn.commit()
     84       conn.close()
     85 
     86       records_list = []
     87       records_need_save = False
     88 
     89       print('>> sqlite insert records: ' + 
     90              str(insert_count * 100) + ' - ' + str(insert_count * 100 + 99))
     91       insert_count = insert_count + 1
     92       time.sleep(0.4)
     93 
     94   print('>> sqlite test finish...')
     95 
     96 if __name__ == '__main__':
     97   main()


    运行结果


    运行test_sqlite.py,显示总共插入10次(每次有100条记录)

    pi@raspberrypi:~ $ python test_sqlite.py

    image


    查看数据库是否存在,显示新生成一个数据库:NULL_999_2020-04-23_160903.db3

    pi@raspberrypi:~ $ cd /home/pi/project/data/tmp/
    pi@raspberrypi:~/project/data/tmp $ ls -lh

    image


    在同一无线网络系啊,使用FileZilla软件登陆树莓派,把数据库文件从树莓派中拷贝到电脑上。

    主机:raspberrypi.local,用户名:pi,密码:raspberry,端口:22,点击 快速连接

    image

    远程站点中,进入/home/pi/project/data/tmp目录

    image

    将下面的数据库文件复制到本地站点的一个目录下(双击或者拖拽都可以):

    image

    SQLite Expert打开这个文件,点击records表,可以看到里面的数据:

    image


    扩展内容:存储逻辑


    >> 存储位置

    创建3个文件夹:<临时>文件夹、<待上传>文件夹、<已上传>文件夹

    临时

    新收到通讯数据时,在该文件夹下建立数据库,持续写入数据;

    持续写入1小时/持续1分钟未收到新数据,关闭该数据库,移动至<待上传>;

    上电后首先将该目录下的数据库文件移动至<待上传>

    待上传

    数据上传服务程序每隔30s扫描一次该目录

    如果有文件,则开始上传第1个文件,上传完成后将该文件移动至<已上传>

    如果采集装置离线,则该目录为实际存储目录

    已上传如果采集装置在线,则该目录为实际存储目录


    >> 批量写入

    为了提高写入效率,可以把记录先放在内存里,攒够N条记录(100条)后再一次性写入到数据库中。当然如果较长的一段时间(10s)没有收到新的数据帧,就会认为被监听的设备掉线,这时把已经有的记录写入到数据库中。


    >> 定时打包

    连续采集较长时间(1个小时),或者连续一段时间(≥1分钟)没有收到新的数据帧,就结束往当前数据库写入记录,相当于把这段时间的数据打包成一个数据库,便于后续使用。把这个数据库移动到待上传的文件夹中,然后再新建一个数据库继续采集。

  • 相关阅读:
    委托demo
    事件demo
    数据结构与算法分析表ADT
    数据结构与算法分析栈ADT
    Access的“自动编号”问题
    C#获取时间函数
    在load事件中关闭窗体
    panel里面显示form的问题
    将RichTextBox 的内容直接写入数据库
    利用反射来创建一个Form.
  • 原文地址:https://www.cnblogs.com/hotwater99/p/12762119.html
Copyright © 2011-2022 走看看