树莓派型号:Zero W
树莓派系统:Raspbian,2018-11-13-raspbian-stretch-lite.img
SD卡:闪迪32G class10 高速Micro SD卡(TF卡)
存储工具:阿里云->对象存储
阿里云的SDK文档(有各种语言的版本,这里选的是Python),提供了上传数据的样例程序:
# -*- coding: utf-8 -*- import oss2 # 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。 auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>') # Endpoint以杭州为例,其它Region请按实际情况填写。 bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', '<yourBucketName>') # <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。 # <yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt。 bucket.put_object_from_file('<yourObjectName>', '<yourLocalFile>')
功能需求
间隔一段时间扫描一次<待上传>目录,如果该目录下有数据文件,就将第一个文件上传到对象存储指定bucket(考虑到以后会有几十台数据采集装置,为了便于管理,每个装置在bucket上有一个专属的二级子目录),上传成功后将这个文件移动到<已上传>目录下。
环境准备
手动创建两个工作目录,分别用于存放<待上传>和<已上传>的数据文件:
mkdir -p ~/project/data/updating
mkdir -p ~/project/data/updated
updating目录下用touch指令创建一个测试文件test.db:
pi@raspberrypi:~ $ cd ~/project/data/updating
pi@raspberrypi:~/project/data/updating $ touch test.db
程序文件
切换到主目录下,创建test_upload.py文件,复制内容进去,保存退出
注意:<yourAccessKeyId>、<yourAccessKeySecret>、<yourBucketName>要改成自己的
pi@raspberrypi:~/project/data/updating $ cd ~
pi@raspberrypi:~ $ sudo nano test_upload.py
1 # -*- coding: utf-8 -*- 2 import os 3 import time 4 import shutil 5 import oss2 6 import ConfigParser 7 8 PRODUCT_TYPE = 'NULL' 9 DEVICE_ID = 999 #default 10 11 #---- 12 def UploadFile_oss2(localfile): 13 global PRODUCT_TYPE 14 global DEVICE_ID 15 16 access_key = '<yourAccessKeyId>' 17 secret_key = '<yourAccessKeySecret>' 18 19 try: 20 auth = oss2.Auth(access_key, secret_key) 21 bucket = oss2.Bucket(auth, 'oss-cn-beijing.aliyuncs.com', '<yourBucketName>') 22 23 # 文件是否存在 24 print '>> uploading local file: ' + localfile 25 if False == os.path.exists(localfile): 26 print '>> local file not exist: ' + localfile 27 return False 28 29 # 根据产品类型、树莓派编号,生成二级目录 30 objectname = PRODUCT_TYPE + '_' + str(DEVICE_ID).rjust(3,'0') \ 31 + '/' + os.path.basename(localfile) 32 print '>> upload result...' 33 result = bucket.put_object_from_file(objectname, localfile) 34 35 print result 36 37 # result.status 200 表示上传成功 38 if result.status == 200: 39 return True 40 else: 41 return False 42 except: 43 return False 44 45 #---- 46 def UploadFile(localfile): 47 return UploadFile_oss2(localfile) 48 49 #---- 50 def main(): 51 global PRODUCT_TYPE 52 global DEVICE_ID 53 54 DB_UPDATING_DIR = '/home/pi/project/data/updating/' 55 DB_UPDATED_DIR = '/home/pi/project/data/updated/' 56 CONFIG_FILE = '/home/pi/project/config.ini' 57 file_path = '' 58 59 # time.sleep(10) 60 # 读取产品类型、树莓派编号 61 GetDeviceInfo(CONFIG_FILE) 62 63 print '>> uploading scheduler start...' 64 while True: 65 filelist = os.listdir(DB_UPDATING_DIR) 66 if len(filelist) > 0: 67 # 获得<待上传>文件夹下的第一个数据文件 68 file_path = os.path.join(DB_UPDATING_DIR, filelist[0]) 69 if os.path.exists(file_path): 70 print '>> file need upload: ' + file_path 71 if True == UploadFile(file_path): 72 # 上传成功,将数据文件放到<已上传>文件夹中 73 MoveFile(file_path, DB_UPDATED_DIR) 74 print '>> upload succeed: '+ file_path 75 76 # 每隔一段时间扫描一次<待上传>文件夹(每小时生成一个新的数据文件) 77 time.sleep(30) 78 79 #---- 80 def GetDeviceInfo(file_path): 81 global PRODUCT_TYPE 82 global DEVICE_ID 83 84 # 读取配置信息 85 PRODUCT_TYPE = 'NULL' 86 DEVICE_ID = 999 87 ''' 88 try: 89 config = ConfigParser.ConfigParser() 90 config.read(file_path) 91 if "device" in config.sections(): 92 PRODUCT_TYPE = config.get("device", "type") 93 DEVICE_ID = config.getint("device", "id") 94 except: 95 # 配置文件加载异常,使用默认参数:产品类型NULL 树莓派编号999 96 PRODUCT_TYPE = 'NULL' 97 DEVICE_ID = 999 98 ''' 99 100 #---- 101 def MoveFile(src_file_path, dst_folder_path): 102 try: 103 if not os.path.exists(dst_folder_path): 104 os.mkdir(dst_folder_path) 105 shutil.move(src_file_path, dst_folder_path) 106 except: 107 return 108 109 #---- 110 if __name__ == '__main__': 111 main()
>> def UploadFile_oss2(localfile):
这个函数把本地文件上传到阿里云对象存储的buckek空间。
基本是按照官方提供的样例程序写的,加了一些防止异常的冗余代码。
上传时使用二次子目录,直接在objectname加上目录就可以了 :
objectname = 'NULL_999/' + os.path.basename(localfile)
上传结果result.status为200表示上传成功。
>> def UploadFile(localfile):
调用UploadFile_oss2,隔离一下,万一要改成其他云。
>> def GetDeviceInfo(file_path):
获取设备信息:产品信号、设备编号,每个设备根据这个信息,可以在bucket空间上创建专属的二级子目录,便于管理数据。
这些设置信息保存在一个配置文件中,用ConfigParser库进行访问,为了简化操作现在这段代码暂时注释掉了,直接使用默认的设备信息。
>> def MoveFile(src_file_path, dst_folder_path):
文件上传成功后,从<待上传>移动到<已上传>。
如果目标目录不存在,使用os库创建该目录;使用shutil库进行文件移动操作。
>> def main():
间隔一段时间扫描一次<待上传>目录,上传该目录下的第一个文件。
filelist = os.listdir(DB_UPDATING_DIR),获得该目录下的文件清单
os.path.join(DB_UPDATING_DIR, filelist[0]),获得第一个文件的路径
运行测试
运行test_upload.py,显示数据上传成功
pi@raspberrypi:~ $ python test_upload.py
切换到updated目录下,文件已经移动过来了
pi@raspberrypi:~ $ cd ~/project/data/updated
pi@raspberrypi:~/project/data/updated $ ls
打开阿里云app,管控->文件管理->xxxx_bucket_name,多了一个NULL_999的二级目录,进入该目录,test.db文件已经上传成功了。