python实现FTP文件上传

2023-11-17

1.需求

   通过python web server端上传大文件到FTP服务端,上传文件夹,下载文件等

1.代码

#!/usr/bin/python
# -*- coding: UTF-8 -*-


from ftplib import FTP
import os
import sys
import time
import socket


class MyFTP:
    """
        ftp自动下载、自动上传脚本,可以递归目录操作
        作者:欧阳鹏
        博客地址:http://blog.csdn.net/ouyang_peng/article/details/79271113
    """

    def __init__(self, host, port=21):
        """ 初始化 FTP 客户端
        参数:
                 host:ip地址

                 port:端口号
        """
        # print("__init__()---> host = %s ,port = %s" % (host, port))

        self.host = host
        self.port = port
        self.ftp = FTP()
        # 重新设置下编码方式
        self.ftp.encoding = 'gbk'
        self.log_file = open("log.txt", "a")
        self.file_list = []

    def login(self, username, password):
        """ 初始化 FTP 客户端
            参数:
                  username: 用户名

                 password: 密码
            """
        try:
            timeout = 60
            socket.setdefaulttimeout(timeout)
            # 0主动模式 1 #被动模式
            self.ftp.set_pasv(False)
            # 打开调试级别2,显示详细信息
            # self.ftp.set_debuglevel(2)

            self.debug_print('开始尝试连接到 %s' % self.host)
            self.ftp.connect(self.host, self.port)
            self.debug_print('成功连接到 %s' % self.host)

            self.debug_print('开始尝试登录到 %s' % self.host)
            self.ftp.login(username, password)
            self.debug_print('成功登录到 %s' % self.host)

            self.debug_print(self.ftp.welcome)
        except Exception as err:
            self.deal_error("FTP 连接或登录失败 ,错误描述为:%s" % err)
            pass

    def is_same_size(self, local_file, remote_file):
        """判断远程文件和本地文件大小是否一致

           参数:
             local_file: 本地文件

             remote_file: 远程文件
        """
        try:
            remote_file_size = self.ftp.size(remote_file)
        except Exception as err:
            # self.debug_print("is_same_size() 错误描述为:%s" % err)
            remote_file_size = -1

        try:
            local_file_size = os.path.getsize(local_file)
        except Exception as err:
            # self.debug_print("is_same_size() 错误描述为:%s" % err)
            local_file_size = -1

        self.debug_print('local_file_size:%d  , remote_file_size:%d' % (local_file_size, remote_file_size))
        if remote_file_size == local_file_size:
            return 1
        else:
            return 0

    def download_file(self, local_file, remote_file):
        """从ftp下载文件
            参数:
                local_file: 本地文件

                remote_file: 远程文件
        """
        self.debug_print("download_file()---> local_path = %s ,remote_path = %s" % (local_file, remote_file))

        if self.is_same_size(local_file, remote_file):
            self.debug_print('%s 文件大小相同,无需下载' % local_file)
            return
        else:
            try:
                self.debug_print('>>>>>>>>>>>>下载文件 %s ... ...' % local_file)
                buf_size = 1024
                file_handler = open(local_file, 'wb')
                self.ftp.retrbinary('RETR %s' % remote_file, file_handler.write, buf_size)
                file_handler.close()
            except Exception as err:
                self.debug_print('下载文件出错,出现异常:%s ' % err)
                return

    def download_file_tree(self, local_path, remote_path):
        """从远程目录下载多个文件到本地目录
                       参数:
                         local_path: 本地路径

                         remote_path: 远程路径
                """
        print("download_file_tree()--->  local_path = %s ,remote_path = %s" % (local_path, remote_path))
        try:
            self.ftp.cwd(remote_path)
        except Exception as err:
            self.debug_print('远程目录%s不存在,继续...' % remote_path + " ,具体错误描述为:%s" % err)
            return

        if not os.path.isdir(local_path):
            self.debug_print('本地目录%s不存在,先创建本地目录' % local_path)
            os.makedirs(local_path)

        self.debug_print('切换至目录: %s' % self.ftp.pwd())

        self.file_list = []
        # 方法回调
        self.ftp.dir(self.get_file_list)

        remote_names = self.file_list
        self.debug_print('远程目录 列表: %s' % remote_names)
        for item in remote_names:
            file_type = item[0]
            file_name = item[1]
            local = os.path.join(local_path, file_name)
            if file_type == 'd':
                print("download_file_tree()---> 下载目录: %s" % file_name)
                self.download_file_tree(local, file_name)
            elif file_type == '-':
                print("download_file()---> 下载文件: %s" % file_name)
                self.download_file(local, file_name)
            self.ftp.cwd("..")
            self.debug_print('返回上层目录 %s' % self.ftp.pwd())
        return True

    def upload_file(self, local_file, remote_file):
        """从本地上传文件到ftp

           参数:
             local_path: 本地文件

             remote_path: 远程文件
        """
        if not os.path.isfile(local_file):
            self.debug_print('%s 不存在' % local_file)
            return

        if self.is_same_size(local_file, remote_file):
            self.debug_print('跳过相等的文件: %s' % local_file)
            return

        buf_size = 1024
        file_handler = open(local_file, 'rb')
        self.ftp.storbinary('STOR %s' % remote_file, file_handler, buf_size)
        file_handler.close()
        self.debug_print('上传: %s' % local_file + "成功!")

    def upload_file_tree(self, local_path, remote_path):
        """从本地上传目录下多个文件到ftp
           参数:

             local_path: 本地路径

             remote_path: 远程路径
        """
        if not os.path.isdir(local_path):
            self.debug_print('本地目录 %s 不存在' % local_path)
            return
        """
        创建服务器目录
        """
        try:
            self.ftp.cwd(remote_path)  # 切换工作路径
        except Exception as e:
            base_dir, part_path = self.ftp.pwd(), remote_path.split('/')
            for p in part_path[1:-1]:
                base_dir = base_dir + p + '/'  # 拼接子目录
                try:
                    self.ftp.cwd(base_dir)  # 切换到子目录, 不存在则异常
                except Exception as e:
                    print('INFO:', e)
                    self.ftp.mkd(base_dir)  # 不存在创建当前子目录
        #self.ftp.cwd(remote_path)
        self.debug_print('切换至远程目录: %s' % self.ftp.pwd())

        local_name_list = os.listdir(local_path)
        self.debug_print('本地目录list: %s' % local_name_list)
        #self.debug_print('判断是否有服务器目录: %s' % os.path.isdir())

        for local_name in local_name_list:
            src = os.path.join(local_path, local_name)
            print("src路径=========="+src)
            if os.path.isdir(src):
                try:
                    self.ftp.mkd(local_name)
                except Exception as err:
                    self.debug_print("目录已存在 %s ,具体错误描述为:%s" % (local_name, err))
                self.debug_print("upload_file_tree()---> 上传目录: %s" % local_name)
                self.debug_print("upload_file_tree()---> 上传src目录: %s" % src)
                self.upload_file_tree(src, local_name)
            else:
                self.debug_print("upload_file_tree()---> 上传文件: %s" % local_name)
                self.upload_file(src, local_name)
        self.ftp.cwd("..")

    def close(self):
        """ 退出ftp
        """
        self.debug_print("close()---> FTP退出")
        self.ftp.quit()
        self.log_file.close()

    def debug_print(self, s):
        """ 打印日志
        """
        self.write_log(s)

    def deal_error(self, e):
        """ 处理错误异常
            参数:
                e:异常
        """
        log_str = '发生错误: %s' % e
        self.write_log(log_str)
        sys.exit()

    def write_log(self, log_str):
        """ 记录日志
            参数:
                log_str:日志
        """
        time_now = time.localtime()
        date_now = time.strftime('%Y-%m-%d', time_now)
        format_log_str = "%s ---> %s \n " % (date_now, log_str)
        print(format_log_str)
        self.log_file.write(format_log_str)

    def get_file_list(self, line):
        """ 获取文件列表
            参数:
                line:
        """
        file_arr = self.get_file_name(line)
        # 去除  . 和  ..
        if file_arr[1] not in ['.', '..']:
            self.file_list.append(file_arr)

    def get_file_name(self, line):
        """ 获取文件名
            参数:
                line:
        """
        pos = line.rfind(':')
        while (line[pos] != ' '):
            pos += 1
        while (line[pos] == ' '):
            pos += 1
        file_arr = [line[0], line[pos:]]
        return file_arr


if __name__ == "__main__":
    my_ftp = MyFTP("192.168.169.3")
    #my_ftp.set_pasv(False)
    my_ftp.login("ftpuser", "123456")

    # 下载单个文件
    #my_ftp.download_file("/home/BG_2019_05_22_16_04_54_Camera6-0.mp4", "/BG_2019_05_22_16_04_54_Camera6-0.mp4") #FTP服务器目录   本地目录

    # 下载目录
    # my_ftp.download_file_tree("G:/ftp_test/", "App/AutoUpload/ouyangpeng/I12/")

    # 上传单个文件
    # my_ftp.upload_file("G:/ftp_test/Release/XTCLauncher.apk", "/App/AutoUpload/ouyangpeng/I12/Release/XTCLauncher.apk")

    # 上传目录
    my_ftp.upload_file_tree("/home/zoukaicai/java8", "/123/5/")

    my_ftp.close()

参考链接:https://blog.csdn.net/ouyang_peng/article/details/79271113

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python实现FTP文件上传 的相关文章

  • 使用 MongoDB 作为我们的主数据库,我应该使用单独的图数据库来实现实体之间的关系吗?

    我们目前正在为一家专业公司内部实施类似 CRM 的解决方案 由于存储信息的性质以及信息的不同值和键 我们决定使用文档存储数据库 因为它完全适合目的 在本例中我们选择 MongoDB 作为此 CRM 解决方案的一部分 我们希望存储实体之间的关
  • Gunicorn 工作人员无论如何都会超时

    我正在尝试通过gunicorn运行一个简单的烧瓶应用程序 但是无论我做什么 我的工作人员都会超时 无论是否有针对应用程序的活动 工作人员在我设置任何内容后总是会超时timeout值到 是什么导致它们超时 当我发出请求时 请求成功通过 但工作
  • 在 Python 中将列表元素作为单独的项目返回

    Stackoverflow 的朋友们大家好 我有一个计算列表的函数 我想单独返回列表的每个元素 如下所示 接收此返回的函数旨在处理未定义数量的参数 def foo my list 1 2 3 4 return 1 2 3 4 列表中的元素数
  • 多输出堆叠回归器

    一次性问题 我正在尝试构建一个多输入堆叠回归器 添加到 sklearn 0 22 据我了解 我必须结合StackingRegressor and MultiOutputRegressor 经过多次尝试 这似乎是正确的顺序 import nu
  • VSCode Settings.json 丢失

    我正在遵循教程 并尝试将 vscode 指向我为 Scrapy 设置的虚拟工作区 但是当我在 VSCode 中打开设置时 工作区设置 选项卡不在 用户设置 选项卡旁边 我还尝试通过以下方式手动转到文件 APPDATA Code User s
  • 在 Django Admin 中调整字段大小

    在管理上添加或编辑条目时 Django 倾向于填充水平空间 但在某些情况下 当编辑 8 个字符宽的日期字段或 6 或 8 个字符的 CharField 时 这确实是一种空间浪费 字符宽 然后编辑框最多可容纳 15 或 20 个字符 我如何告
  • Python 3d 绘图设置固定色阶

    我正在尝试绘制两个 3d 数组 第一个数组的 z 值在范围内 0 15 0 15 第二个来自 0 001 0 001 当我绘图时 色标自动遵循数据范围 如何设置自定义比例 我不想看到 0 001 的浅色 而应该看到 0 15 的浅色 如何修
  • 为什么 web2py 在启动时崩溃?

    我正在尝试让 web2py 在 Ubuntu 机器上运行 所有文档似乎都表明要在 nix 系统上运行它 您需要下载源代码并执行以下操作 蟒蛇 web2py py 我抓住了source http www web2py com examples
  • GUI(输入和输出矩阵)?

    我需要创建一个 GUI 将数据输入到矩阵或表格中并读取此表单数据 完美的解决方案是限制输入表单仅允许float 例如 A 1 02 0 25 0 30 0 515 0 41 1 13 0 15 1 555 0 25 0 14 1 21 2
  • 使用 Python Oauthlib 通过服务帐户验证 Google API

    我不想使用适用于 Python 的 Google API 客户端库 但仍想使用 Python 访问 Google APIOauthlib https github com idan oauthlib 创建服务帐户后谷歌开发者控制台 http
  • 未知错误:Chrome 无法启动:异常退出

    当我使用 chromedriver 对 Selenium 运行测试时 出现此错误 selenium common exceptions WebDriverException Message unknown error Chrome fail
  • python的shutil.move()在linux上是原子的吗?

    我想知道python的shutil move在linux上是否是原子的 如果源文件和目标文件位于两个不同的分区上 行为是否不同 或者与它们存在于同一分区上时的行为相同吗 我更关心的是如果源文件和目标文件位于同一分区上 shutil move
  • 通过Python连接到Bigquery:ProjectId和DatasetId必须非空

    我编写了以下脚本来通过 SDK 将 Big Query 连接到 Python 如下所示 from google cloud import bigquery client bigquery Client project My First Pr
  • 找到一个数字所属的一组范围

    我有一个 200k 行的数字范围列表 例如开始位置 停止位置 该列表包括除了非重叠的重叠之外的所有类型的重叠 列表看起来像这样 3 5 10 30 15 25 5 15 25 35 我需要找到给定数字所属的范围 并对 100k 个数字重复该
  • 在 Google App Engine 中,如何避免创建具有相同属性的重复实体?

    我正在尝试添加一个事务 以避免创建具有相同属性的两个实体 在我的应用程序中 每次看到新的 Google 用户登录时 我都会创建一个新的播放器 当新的 Google 用户在几毫秒内进行多个 json 调用时 我当前的实现偶尔会创建重复的播放器
  • 为什么 csv.DictReader 给我一个无属性错误?

    我的 CSV 文件是 200 Service 我放入解释器的代码是 snav csv DictReader open screennavigation csv delimiter print snav fieldnames 200 for
  • python 中的“槽包装器”是什么?

    object dict 和其他地方的隐藏方法设置为这样的
  • Python:Goslate 翻译请求返回“503:服务不可用”[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我们不允许提出寻求书籍 工具 软件库等推荐的问题 您可以编辑问题 以便用事实和引文来回答 这个问题似乎不是关于主要由程序员使用的特定编程问
  • 重新分配唯一值 - pandas DataFrame

    我在尝试着assign unique值在pandas df给特定的个人 For the df below Area and Place 会一起弥补unique不同的价值观jobs 这些值将分配给个人 总体目标是使用尽可能少的个人 诀窍在于这
  • JSON:TypeError:Decimal('34.3')不是JSON可序列化的[重复]

    这个问题在这里已经有答案了 我正在运行一个 SQL 查询 它返回一个小数列表 当我尝试将其转换为 JSON 时 出现类型错误 查询 res db execute SELECT CAST SUM r SalesVolume 1000 0 AS

随机推荐

  • [网络安全自学篇] 三.Burp Suite安装配置、Proxy基础用法及流量分析示例

    最近开始学习网络安全相关知识 接触了好多新术语 感觉自己要学习的东西太多 真是学无止境 也发现了好几个默默无闻写着博客 做着开源的大神 接下来系统分享一些网络安全的自学笔记 希望读者们喜欢 上一篇文章分享了Chrome浏览器保留密码功能渗透
  • vue的transition动画条上下跳动

    vue部分
  • Dynamics 365 DevOps CI/CD之ConfigurationData

    ConfigurationData如省市区 门店地址这种业务类型的数据 还有系统自定义过程中配置或开发涉及的参数 需要在系统间进行同步 此处CI用到了Power Platform Tool这个工具 这个也是可以在Azure DevOps的商
  • 进度条程序

    package progressbar import java awt BorderLayout import java awt Container import java awt Dimension import java util Ar
  • java中FileReader的使用

    package com test io01 import java io File import java io FileNotFoundException import java io FileReader import java io
  • TTreeNode编程思路

    导读 TTreeNode编程思路 本问以TreeView为例子讲述 其他的用到TTreeNodes的控件的编程思想如出一辙 TreeView由节点构成 建树通过对TreeView items属性进行操作 Items是一个TTreeNodes
  • Redis 配置文件最佳解析

    配置文件 https raw githubusercontent com redis redis 7 0 redis conf 通用模板 引入 include 用于引入其他配置文件 支持使用通配符 根据从上到下的顺序 读取配置项 对同一个配
  • 解决vite首次加载很慢的问题

    目录 vite很快吗 为什么说vite快 为什么说vite慢 解决方案 附加 vite很快吗 vite要比webpack快 是的 真的很快 但个人感受 默认情况下 vite项目的启动确实比webpack快 但如果某个界面是首次进入 且依赖比
  • LaTex希腊字母大全

    小写字母 LaTex指令 大写字母 LaTex指令 alpha alpha A A
  • MySql修改主键字段

    一 应用实例 去除原来的主键字段的主键 ALTER TABLE mdm customer DROP PRIMARY KEY 新增字段并设置为主键 ALTER TABLE mdm customer ADD ID int 32 PRIMARY
  • 【图像处理】数码相机工作原理完整解析

    在过去二十年里 消费电子产品的大多数重要技术突破实际上可归结于一项更大意义上的科技革命 仔细观察就会发现 CD DVD 高清电视 MP3和DVR其实都是基于相同的原理 即 将传统的模拟信息转变为数字信息 这一技术上的根本转变完全颠覆了我们处
  • Tomcat中server.xml中访问多个项目的配置

    Tomcat中server xml中访问多个项目的配置 server xml作为 tomcat 启动时的配置依据 其功能包含了配置访问端口 访问路径等 这里主要针对在同一个 tomcat 中发布多个项目 其中最关键的配置是 标签下appBa
  • 码农的自我修养 - ARM编译器的区分

    在嵌入式软件开发的编码中 有时使用的一些指令是和编译器相关的 这时就要判断当前使用的编译器类型 不同的编译器 会定义不同的宏来进行识别 比如在ARM开发工具包中 cortex M系列开发中 CMSIS Cortex Mx Core Peri
  • SSH工作原理&Ubuntu20.04安装并配置SSH&设置SSH免密登录

    目录 一 SSH的介绍 服务器端 客户端 1 SSH 远程连接工具 连接原理 2 SSH的安全机制 3 两种级别的验证方法 登录方法 二 ssh的安装与启动 1 安装 2 启动服务器的SSH服务 三 SSH客户端 1 前置知识 2 口令登录
  • 最新版SpringBoot整合Mybatis,实现增删改查(CRUD)

    SpringBoot整合Mybatis实现增删改查 文章目录 SpringBoot整合Mybatis实现增删改查 前言 第一 创建MySQL数据库 第二 创建SpringBoot项目 引入需要的依赖包 第三 创建程序目录和配置核心appli
  • matlab实现留一交叉验证,留出法和交叉验证

    写论文的时候涉及到了这两种方法 这里进行总结 评估方法 主要分三种 留出法 分一次 互斥集 交叉验证法 分多次 对k折形成多次互斥集 自助法 有放回抽样 留出法 代码如下 function X train y train X test y
  • 小皮面板(phpstudy)上部署 thinkphp项目并成功访问

    每次搞 thinkphp 都忘记怎么步骤 或者是容易访问出错 尤其是重装系统以后 要安装 Apache MySQL PHP等 现在介绍一个集成工具 小皮面板 安装 小皮面板 1 选版本 根据自己电脑具体位数来选择对应的版本 比如 Windo
  • Echarts tooltip.trigger设为‘axis’ 如何自定义 Tooltip的显示

    题记 当echarts折线图中trigger设置为axis时 只想让tooltip自定义显示某一条线上的点的动态信息 Vue3 TS Vue Echarts 1 问题说明 1 现状 如下图所示折线图 当tooltip的trigger属性值设
  • Nvidia GPU 最新计算能力表(CUDA Compute Capability)

    对于深度学习 官方指出在GPU算力高于5 0时 可以用来跑神经网络 Jetson Products GPU Compute Capability Jetson AGX Xavier 7 2 Jetson Nano 5 3 Jetson TX
  • python实现FTP文件上传

    1 需求 通过python web server端上传大文件到FTP服务端 上传文件夹 下载文件等 1 代码 usr bin python coding UTF 8 from ftplib import FTP import os impo