micropython 使用 requests 库下载文件 库源码:requests github
socket 中文文档:http://micropython.86x.net/en/latet/library/socket.html
socket 英文文档:https://docs.micropython.org/en/latest/library/socket.html
本地HTTP服务器 启动用于测试的简单本地HTTP服务器: https://www.cnblogs.com/shengshengwang/p/17939492
运行这个命令后,默认会在当前目录下启动一个 HTTP 服务器,监听在本地的 8000 端口。可以通过浏览器访问 http://localhost:8000 来查看当前目录的文件列表。 也可以自定义端口号 python -m http.server 8888
问题 下面是 requests 库的 content 属性的实现,会通过 socket 库的 read() 函数将数据一次性全部去读到 self._cached 变量,也就是内存中。这种方式在读取小文件时没有问题,但是文件体积稍大一些后就会出现响应缓慢 ,严重的话会爆内存 的情况,毕竟运行 micropython 的嵌入式设备资源都比较紧张。
1 2 3 4 5 6 7 8 9 @property def content (self ): if self._cached is None : try : self._cached = self.raw.read() finally : self.raw.close() self.raw = None return self._cached
解决 参考 python requests 库的用法,链接:https://www.cnblogs.com/hls-code/p/15012629.html
流式下载能满足要求,但是 micropython 的 requests 库并没有 iter_content()
函数的实现。
通过循环,每次读取一定量的数据是否可行?代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 url = "http://xx.xxx.xxx.xxx:8888/yolov8n_224.kmodel" r = libs.requests.get(url, stream=True) if r.status_code == 200: print("Downloading file...") with open('/sdcard/yolov8n_224.kmodel', 'wb') as pic_file: # 保存文件 while True: chunk = r.raw.recv(1024*20) if not chunk: break pic_file.write(chunk) pic_size += len(chunk) print(pic_size) print("Downloading finish") r.close()
提示:在开发板运行代码时注意将 xxx 替换为 http 服务器的 ip,而不是127.0.0.1 或者 localhost;检查拉取和存储的文件名称和路径。
其他
read() 最后一包数据丢失。
使用 r.raw.read(1024) 发现最后一包数据总是收不到,查看 socket 文档 socket.read([size])
有一段说明
This function tries to read as much data as requested (no “short reads”). This may be not possible with non-blocking socket though, and then less data will be returned.
没有短读 :即不会返回“短读取”(即少于请求字节数的数据) 造成最后一包数据丢失。
content() 非常慢
1 2 with open ('/sdcard/6.bmp' , 'wb' ) as pic_file: pic_file.write(r.content)
完整示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 import network,timefrom machine import Pinimport libs.requestsdef WIFI_Connect (): WIFI_LED=Pin(52 , Pin.OUT) wlan = network.WLAN(network.STA_IF) wlan.active(True ) start_time=time.time() if not wlan.isconnected(): print ('connecting to network...' ) for i in range (3 ): wlan.connect('xxxxx' , 'xxxx' ) if wlan.isconnected(): break if wlan.isconnected(): WIFI_LED.value(1 ) while wlan.ifconfig()[0 ] == '0.0.0.0' : pass print ('network information:' , wlan.ifconfig()) return True else : for i in range (3 ): WIFI_LED.value(1 ) time.sleep_ms(300 ) WIFI_LED.value(0 ) time.sleep_ms(300 ) wlan.active(False ) return False def DownloadFile (): pic_size = 0 try : url = "http://192.168.1.100:8888/6.bmp" r = libs.requests.get(url, timeout=None , stream=True ) if r.status_code == 200 : print ("Downloading file..." ) with open ('/sdcard/6.bmp' , 'wb' ) as pic_file: while True : chunk = r.raw.recv(1024 *20 ) if not chunk: break pic_file.write(chunk) pic_size += len (chunk) print (pic_size) print ("Downloading finish" ) r.close() except UnicodeError as e: print ("Unicode error:" , e) except Exception as e: print ("HTTP request error:" , e) WIFI_Connect() DownloadFile()
修改 wifi 文件名 和存储路径