请问如何异步顺序写文件?

请问如何异步顺序写文件?

请问,我这儿有一个m3u8在线链接,想通过python异步的方式去下载成一个ts文件,但异步编程的水平不够,想过用队列或者异步锁去做,但看文档后写的还是不对。下面是完整代码,希望大佬可以基于此帮忙改一版可以顺序写文件的出来,在此感谢。

import re

import requests

import time

import urllib3

import asyncio

import aiofiles

import queue

from typing import List, Dict

import httpx

urllib3.disable_warnings()

# m3u8_path = "https://13.cdn-vod.huaweicloud.com/asset/94a33fb7bb3c6c6b514d7463f4be98ce/play_video/442d776c312aa0b57193ae1deae9f943/cb8db232c9e31a09c25df076c5f71a4d_2.m3u8"

m3u8_path = 'https://13.cdn-vod.huaweicloud.com/asset/e0a13b1737c48e6335b760a3dffaf4cf/play_video/7d5c1d3316918cd9484941c2b468a44e.m3u8'

header = {

"User-Agent":

"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.20 Safari/537.36"

}

def applyUrl(target_url: str, base_url: str) -> str:

if 'http' in target_url:

return target_url

if target_url[0] == '/':

base_url_list = base_url.split('/')

return base_url_list[0] + '//' + base_url_list[2] + target_url

base_url_list = base_url.split('/')

base_url_list.pop()

return '/'.join(base_url_list) + '/' + target_url

async def get_ts_lists(m3u8_path: str) -> List[str]:

ts_urls: List[str] = []

print("正在解析:" + m3u8_path.split("/")[-1])

# 获取m3u8文件内容

async with httpx.AsyncClient(headers=header, verify=False) as client:

res = await client.get(url=m3u8_path)

r = await res.aread()

# 通过正值表达式获取key和ts的链接

# k = re.compile(r"http://.*?\.key") # key的正则匹配

k = re.compile(r'(.*URI="([^"]+))"')

t = re.compile(r".*?.ts") # ts的正则匹配

iv = re.compile(r'(.*IV=([^,\s]+))')

key_url_list = k.findall(r.decode(encoding='utf-8')) # key的url

key_url = key_url_list[0][1] if len(key_url_list) != 0 else ''

iv_s_list = iv.findall(r.decode(encoding='utf-8'))

iv_s = iv_s_list[0][1] if len(iv_s_list) != 0 else ''

ts_urls = t.findall(r.decode(encoding='utf-8')) # ts的url列表

# print('ts urls:', ts_urls)

if len(ts_urls) != 0:

for idx, ts_url in enumerate(ts_urls):

ts_url = applyUrl(ts_url, m3u8_path)

ts_urls[idx] = ts_url

return ts_urls

async def download_m3u8_file(ts_url: str):

global q

res_dict: Dict[str, httpx.Response] = {}

ts_name = ts_url.split("/")[-1] # ts文件名

# 获取ts文件二进制数据

print("正在下载:" + ts_name)

async with httpx.AsyncClient(headers=header, verify=False) as client:

res = await client.get(ts_url)

res_dict.setdefault(ts_name, res)

q.put(res_dict)

async def write_to_file(name: str):

global q

while True:

async with mutex:

if q.qsize() == 0:

break

res = q.get()

item = res.popitem()

ts_name, te_res = item[0], item[1]

async with aiofiles.open(name, "ab") as file:

await file.write(te_res.read())

print("保存成功:" + ts_name)

async def main():

ts_urls = await get_ts_lists(m3u8_path)

await asyncio.gather(*[download_m3u8_file(ts_url) for ts_url in ts_urls])

if __name__ == '__main__':

name = "dream_it_possible.ts"

q = queue.Queue()

mutex = asyncio.Lock()

asyncio.run(main())

asyncio.run(write_to_file(name))

print(name, "下载完成")


回答:

这个可能不仅仅是异步的问题,是写入策略问题,因为这种分切ts组合成整体必须严格按照顺序,且没有其它数据定位手段,所以好的整合策略是分个下载,整体或者说按序写入。
即可以分批下载,最后等全部下载就绪后再一次写入,或者按序下载,前面连续的可以先行写入(不过这样其实效率也不会高什么,还不如等全部下载完了一次性写入)

此外从IO优化角度来说,这种下载会有一些限制(包括本地的,也包括服务器端限制,过多链接反而不好),所以更多的时候会用链接池类似策略来限制链接数量,所以你在处理中也要注意类似问题。

以上是 请问如何异步顺序写文件? 的全部内容, 来源链接: utcz.com/p/938130.html

回到顶部