首页 > 系统相关 >Python实现文件夹上传到Linux服务器(带日志功能)

Python实现文件夹上传到Linux服务器(带日志功能)

时间:2024-11-19 10:40:31浏览次数:1  
标签:remote str Python self 文件夹 file Linux local dir

功能概述

实现一个 FileUploader 类,用于将本地文件夹及其子文件上传到 Linux 服务器的指定目录,并支持:

  1. 冲突处理策略
    • 覆盖:直接覆盖远程文件。
    • 跳过:跳过已存在的远程文件。
    • 重命名:避免冲突,为文件生成唯一名称。
  2. 日志功能
    • 记录上传成功的文件(upload_success.log)。
    • 记录上传失败的文件和原因(upload_failures.log)。
  3. 目录校验和自动创建
    • 自动检测远程目录是否存在,不存在时会创建。

代码实现

import os
import logging
import paramiko

class FileUploader:
    def __init__(self, hostname: str, port: int, username: str, password: str):
        """
        初始化SSH连接参数
        :param hostname: Linux服务器地址
        :param port: SSH端口
        :param username: 登录用户名
        :param password: 登录密码
        """
        self.hostname = hostname
        self.port = port
        self.username = username
        self.password = password
        self.sftp: paramiko.SFTPClient | None = None
        self.ssh_client: paramiko.SSHClient | None = None
        self._init_logging()

    def _init_logging(self) -> None:
        """初始化日志记录"""
        logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
        self.success_logger = logging.getLogger("success_logger")
        self.failure_logger = logging.getLogger("failure_logger")

        success_handler = logging.FileHandler("upload_success.log", mode="w", encoding="utf-8")
        failure_handler = logging.FileHandler("upload_failures.log", mode="w", encoding="utf-8")
        success_handler.setFormatter(logging.Formatter("%(asctime)s - %(message)s"))
        failure_handler.setFormatter(logging.Formatter("%(asctime)s - %(message)s"))

        self.success_logger.addHandler(success_handler)
        self.failure_logger.addHandler(failure_handler)

    def connect(self) -> None:
        """建立SSH和SFTP连接"""
        try:
            self.ssh_client = paramiko.SSHClient()
            self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self.ssh_client.connect(
                hostname=self.hostname,
                port=self.port,
                username=self.username,
                password=self.password
            )
            self.sftp = self.ssh_client.open_sftp()
            print("连接成功")
        except Exception as e:
            raise Exception(f"连接失败: {e}")

    def upload_directory(
        self,
        local_dir: str,
        remote_dir: str,
        conflict_strategy: str = "overwrite"
    ) -> None:
        """
        上传本地文件夹及其子文件到远程文件夹。
        :param local_dir: 本地文件夹路径
        :param remote_dir: 远程目标文件夹路径
        :param conflict_strategy: 冲突处理策略,可选值:
            - "overwrite": 覆盖文件(默认)
            - "skip": 跳过已存在文件
            - "rename": 重命名冲突文件
        """
        if not os.path.exists(local_dir):
            raise FileNotFoundError(f"本地目录不存在: {local_dir}")

        self._ensure_remote_dir(remote_dir)

        for root, _, files in os.walk(local_dir):
            relative_path = os.path.relpath(root, local_dir)
            remote_path = os.path.join(remote_dir, relative_path).replace("\\", "/")

            self._ensure_remote_dir(remote_path)

            for file in files:
                local_file = os.path.join(root, file)
                remote_file = os.path.join(remote_path, file).replace("\\", "/")

                try:
                    if self._check_file_exists(remote_file):
                        if conflict_strategy == "skip":
                            print(f"跳过已存在文件: {remote_file}")
                            continue
                        elif conflict_strategy == "rename":
                            remote_file = self._get_unique_filename(remote_file)
                            print(f"重命名并上传: {local_file} -> {remote_file}")
                        elif conflict_strategy == "overwrite":
                            print(f"覆盖文件: {remote_file}")

                    self.sftp.put(local_file, remote_file)
                    print(f"已上传: {local_file} -> {remote_file}")
                    self.success_logger.info(f"{local_file} -> {remote_file}")

                except Exception as e:
                    print(f"上传失败: {local_file} -> {remote_file},原因: {e}")
                    self.failure_logger.error(f"{local_file} -> {remote_file},原因: {e}")

    def _ensure_remote_dir(self, remote_dir: str) -> None:
        """确保远程目录存在,不存在则创建"""
        try:
            self.sftp.stat(remote_dir)
        except FileNotFoundError:
            self.sftp.mkdir(remote_dir)
            print(f"已创建远程目录: {remote_dir}")

    def _check_file_exists(self, remote_file: str) -> bool:
        """检查远程文件是否存在"""
        try:
            self.sftp.stat(remote_file)
            return True
        except FileNotFoundError:
            return False

    def _get_unique_filename(self, remote_file: str) -> str:
        """生成唯一的文件名以避免冲突"""
        base, ext = os.path.splitext(remote_file)
        counter = 1
        while self._check_file_exists(remote_file):
            remote_file = f"{base}_{counter}{ext}"
            counter += 1
        return remote_file

    def close(self) -> None:
        """关闭SFTP和SSH连接"""
        if self.sftp:
            self.sftp.close()
        if self.ssh_client:
            self.ssh_client.close()
        print("连接已关闭")


if __name__ == "__main__":
    uploader = FileUploader(hostname="192.168.1.1", port=22, username="user", password="password")
    try:
        uploader.connect()
        uploader.upload_directory(
            local_dir="C:/local_folder",
            remote_dir="/remote_folder",
            conflict_strategy="rename"
        )
    finally:
        uploader.close()

功能说明

  1. 参数类型说明

    • hostname (str): 服务器地址。
    • port (int): SSH端口号。
    • username (str): 用户名。
    • password (str): 密码。
    • local_dir (str): 本地目录路径。
    • remote_dir (str): 远程目录路径。
    • conflict_strategy (str): 冲突策略,可选 "overwrite""skip""rename"
  2. 日志功能

    • 成功日志:记录成功上传的文件,保存为 upload_success.log
    • 失败日志:记录失败文件及原因,保存为 upload_failures.log
  3. 冲突处理

    • 覆盖:直接覆盖远程文件。
    • 跳过:跳过已存在的文件。
    • 重命名:为冲突文件自动生成唯一名称。

运行结果示例

  • 成功日志 (upload_success.log):

    2024-11-19 15:00:00 - C:/local_folder/file1.txt -> /remote_folder/file1.txt
    
  • 失败日志 (upload_failures.log):

    2024-11-19 15:01:00 - C:/local_folder/file3.txt -> /remote_folder/file3.txt,原因: Permission denied
    

适用场景

  • 定时备份本地文件到远程服务器。
  • 上传大规模文件夹时自动处理冲突。
  • 记录上传操作的成功和失败,便于问题排查。

标签:remote,str,Python,self,文件夹,file,Linux,local,dir
From: https://www.cnblogs.com/echohye/p/18554407

相关文章

  • python爬虫-使用requests库和BeautifuSoup库爬取静态网页
    目前在自学python中,作此记录,欢迎交流。此次练手对象为爬取中国大学排名内容并进行输出;总的思路如下:1、选取一个网站,观察所需要的信息位置网站链接:中国大学排名_高校排名_中国大学排行榜-中国教育在线当前页面右键鼠标,选择查看源代码,观察所需内容位置:可以看到内容保存在d......
  • JAVA WEB 实现文件夹上传(保留目录结构)分享
    需求:大文件上传,批量上传,断点续传,文件夹上传,大文件下载,批量下载,断点下载,文件夹下载文件夹:上传下载需要支持层级结构,采用非压缩方式文件大小:100G前端:vue2,vue3,vue-cli,jquery,html,webuploader后端:JSP,springbootweb服务:tomcat数据库:mysql,oracle,达梦,国产化数据库服务......
  • python-爬取网站天气数据-1
    一、选择一个网站,观察需要的内容位置这次练手对象是一个2345网站天气数据,如下:南京历史天气查询_历史天气预报查询_2345天气预报这里面我想要获得的天气数据如上图,我需要将这些数据爬取下来并保存为本地文件。二、查看代码,观察内容信息在代码中所处的位置右键,选择查看源代......
  • Linux 链式与层级中断控制器讲解:原理与驱动开发
    往期内容本专栏往期内容,interrtupr子系统:深入解析Linux内核中断管理:从IRQ描述符到irqdomain的设计与实现Linux内核中IRQDomain的结构、操作及映射机制详解中断描述符irq_desc成员详解Linux内核中断描述符(irq_desc)的初始化与动态分配机制详解中断的硬件框架GIC介绍......
  • Python爬虫(爬取博客网为例)
    一、前言场景1:一个网络爬虫,顺序爬取一个网页花了一个小时,采用并发下载就减少到了20分钟。场景2:一个应用软件优化前每次打开网页需要3秒,采用异步并发提升到了200毫秒。假设一个工程的工作量为100,不采用并发编程就相当于由一个人去完成这个工作量为100的所有工作内容,可能需要1......
  • Python中的平方功能:方便实用的数据处理利器
    Python作为一门广泛应用于数据科学、机器学习和人工智能领域的编程语言,具有许多实用的功能。其中,Python中的平方功能是一个非常有用和实用的数据处理利器。简洁易用的语法Python中的平方功能使用的是**运算符,其语法为**数**,其中数可以是任意实数、整数或字符串。例如,要计......
  • Python用subprocess管理子进程在Windows平台实现平行效果
    在Python中,使用subprocess模块管理子进程时,如果你在Windows平台上尝试实现类似于Unix系统的“平行效果”(即父子进程可以同时运行),你可能会遇到一些问题。在Unix系统中,子进程是独立于父进程的,它们可以同时运行。但在Windows系统中,当你使用subprocess创建子进程时,默认情况下会存在父......
  • 《Python从入门到实践》第四章动手试一试
    4-1比萨:想出至少三种你喜欢的比萨,将其名称存储在一个列表中,再使用for循环将每种比萨的名称都打印出来。修改这个for循环,使其打印包含比萨名称的句子,而不仅仅是比萨的名称。对于每种比萨,都显示一行输出,如“Ilikepepperonipizza”。在程序末尾添加一行代码,它不在for循环中,指......
  • Python设计模式详解之1 —— 单例模式
    单例模式(SingletonPattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供全局访问点。单例模式适用于需要确保全局唯一实例的场景,例如配置管理、日志记录器、数据库连接等。1.单例模式的特点全局唯一性:在整个应用程序的生命周期内,单例类只能有一个实例。全局访问:......
  • AlmaLinux 9.5 正式版发布 - RHEL 二进制兼容免费发行版
    AlmaLinux9.5正式版发布-RHEL二进制兼容免费发行版由社区提供的免费Linux操作系统,RHEL二进制兼容发行版请访问原文链接:https://sysin.org/blog/almalinux-9/查看最新版。原创作品,转载请保留出处。作者主页:sysin.org由社区提供的免费Linux操作系统一个开源、社区......