基于 python 用 fastapi 或 http 标准库架一个下载服务器里的文件或目录的临时服务,附客户端代码

急的话请看这里标准库http的用法

  1. python -m http.server [指定端口号,默认是8000] 即可访问服务器,并默认基于当前目录作交互,后文将称其为服务根目录(如下载、查看文件等交互)
  2. 浏览器访问http://<作为服务器的IP>:<指定的端口号,默认是8000>点击要下载的文件,或者wget, curl 等.
  3. (可选,但笔者常用)直接下载文件的方法,命令行终端用wgetcurl等网络请求工具输入,或者就浏览器输入如下 URL 即可下载文件:
    1. wget 下载某个文件
      http://<作为服务器的IP>:<指定的端口号,默认是8000>/<相对于服务根目录的文件路径>

    2. wget 下载目录下的所有文件(参考https://blog.csdn.net/qq_35793285/article/details/89879693
      wget -r -np -nH -R index.html http://<IP>:<PORT>/<要下载的目录下的文件, 不指定则下载服务根目录下的所有文件>

      各个参数的含义:

      • -r : 遍历所有子目录
      • -np : 不到上一层子目录去
      • -nH : 不要将文件保存到主机名文件夹
      • -R index.html : 不下载 index.html 文件

Besides 修改端口、交互目录的方法请输入python -m http.server --help

FastAPI 的下载服务介绍

  • 服务端(具体文件路径怎么定位,读者可自行定义,不一定按查询参数的形式)

    from fastapi import FastAPI, HTTPException
    from fastapi.responses import FileResponse, StreamingResponse
    import os
    import zipfile
    import io
    
    app = FastAPI()
    
    
    def create_zip_from_dir(dir_path: str, zip_buffer: io.BytesIO) -> None:
        """将指定目录打包成ZIP文件并写入缓冲区"""
        with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zipf:
            for root, dirs, files in os.walk(dir_path):
                for file in files:
                    file_path = os.path.join(root, file)
                    zipf.write(file_path, os.path.relpath(file_path, dir_path))
    
    
    @app.get("/download")
    async def download(file_or_dir_name: str):
        file_path = f"path/to/{file_or_dir_name}"
        print(f'download {file_path}')
    
        if os.path.isdir(file_path):
            # 如果是目录,则创建ZIP压缩文件
            print(f'zipping directory {file_path}')
            zip_buffer = io.BytesIO()
            create_zip_from_dir(file_path, zip_buffer)
            zip_buffer.seek(0)  # 将读取指针移到开头
            return StreamingResponse(
                zip_buffer,
                media_type="application/x-zip-compressed",
                headers={
                    "Content-Disposition": f"attachment; filename={file_or_dir_name}.zip"
                },
            )
        elif os.path.isfile(file_path):
            # 如果是文件,直接返回文件
            return FileResponse(
                file_path, media_type="application/octet-stream", filename=file_or_dir_name
            )
        else:
            # 文件或目录不存在
            raise HTTPException(status_code=404, detail="File or directory not found")
    
    
    if __name__ == "__main__":
        import uvicorn
    
        uvicorn.run(app, host="0.0.0.0", port=6666)
    
  • 客户端

    1. 浏览器请求
      http://<你的服务器IP>:6666/download?file_or_dir_name=<服务器上的文件或目录>
      若下载的是目录则通常浏览器自己会根据服务器上的目录路径打包成.zip文件,最后请到浏览器的下载目录查看,并手动解压
    2. python请求
      import os
      import zipfile
      import io
      import requests
      
      
      def download(
          target, host=f"http://{你的服务器IP}", port=6666, path="/download", save_dir="./tmp"
      ):
          target = target[:-1] if target.endswith("/") else target
          local_filename = os.path.join(save_dir, os.path.basename(target))
          os.makedirs(save_dir, exist_ok=True)
      
          url = f"{host}:{port}{path}"
          with requests.get(url, params=f'file_or_dir_name={target}', stream=True) as r:
              r.raise_for_status()
      
              # 如果是 zip 文件,则解压到本地目录
              content_type = r.headers.get('Content-Type')
              if content_type in ['application/zip', 'application/x-zip-compressed']:
                  with zipfile.ZipFile(io.BytesIO(r.content)) as zipped:
                      zipped.extractall(save_dir)
              elif content_type == 'application/octet-stream':
                  # 如果响应状态码不是200,将抛出异常
                  with open(local_filename, "wb") as f:
                      for chunk in r.iter_content(chunk_size=8192):
                          # 使用分块传输,适合大文件下载
                          if chunk:  # filter out keep-alive new chunks
                              f.write(chunk)
              else:
                  raise ValueError(f'下载到意外的 MIME 类型: {content_type}')
      
      
      if __name__ == "__main__":
      	# 下载服务器上的 model 目录
          download(
              target="project/deploy/model/"
          )
      

感谢各开源的前辈😄

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值