FTP与SFTP传输文件的Python、shell脚本

文章目录

前言

在工作中我们经常遇到在不同的电脑之间传输文件,有时是同一网络下,有时是不同的网络之间传输文件,甚至是向客户传输文件。本文主要介绍常用的两种传输方式:FTP和SFTP,以及Python和shell脚本实现。

或许你会说,传文件嘛,U盘拷一下喽,QQ、微信、邮箱等都可以呀!

是的,方法有很多,但是如果每天都要你定时传一份文件给对方呢?你天天定时去插U盘拔U盘吗?

对于同一网络之间的电脑,我们可以在一台机器上设置一个共享目录,然后其他的电脑挂载这一个共享目录,这样就不用互传了。对于不同网络之间,或者与客户之间传输文件,平常工作中常用的还是通过FTP或SFTP

FTP与SFTP简介与区别

FTP是一种文件传输协议,用于文件之间的双向传输,同时又是一个应用程序,包括一个FTP服务器和多个FTP客户端,FTP客户端通过FTP协议向服务器上传文件或从服务器下载文件。

SFTP是一种安全的文件传送协议,是ssh内含协议,也就是说只要SSH服务器启动了,SFTP就可使用,不需要额外安装,它的默认端口和SSH一样为22。

SFTP通过使用加密/解密技术来保障传输文件的安全性,因此SFTP的传输效率比普通的FTP要低,但SFTP的安全性要比FTP高,因此SFTP通常用于报表、对账单等对安全性要求较高的场景。

废话不多说,想了解更多详情请自行百度Google。

脚本实现

如果是偶尔一次传输文件,可以使用命令行的方式交互的传输文件,但如果作为定时任务或者经常性的工作就要写脚本自动传输文件。接下来,介绍在shell和Python中如何实现FTP和SFTP的文件传输。

FTP

交互式的互传文件首先要登录FTP,登录方式有两种:

1、使用命令 ftp host port

2、先使用命令 ftp ,然后使用命令:open host port

在这里插入图片描述
然后根据提示输入用户名和密码。成功登录后就可以传输文件了,传输文件中常用的命令有:

cd remote-directory :切换进入远程工作目录
lcd local-directory:切换进入本地工作目录
binary:设置为二进制传输
get remote-file [local-file]:下载远程文件到本地
mkdir directory-name :在远程机器上创建文件夹
put local-file [remote-file] : 上传本地文件到远程机器
pwd :打印远程机器的当前工作目录
rmdir directory-name : 删除远程机器上的目录

还有许多其他的命令,可以使用info ftp 查看更多命令详情。

如果作为定时任务,每天都要上传或下载一份文件,那么交互式的方式就不行,可以使用自动上传下载的方式,shell脚本如下:

ftp -v -n<<EOF
open host port
user abc ***
binary
lcd /service/data
prompt
mkdir 20181015
cd 20181015
put 20181015.zip
close
bye
EOF

其中-v:程序运行时显示详细的处理信息,-n:关闭自动登录功能,prompt:关闭交互模式。这样可以将上述脚本写入.sh文件,将日期作为变量,每天执行.sh文件就行了,如下:

#!/bin/bash
TODAY=$(date +%Y%m%d)
TODAY_NAME=$(date +%m%d)
ftp -v -n<<EOF
open host port
user abc ***
binary
lcd /service/data
prompt
mkdir ${TODAY}
cd ${TODAY}
put ${TODAY_NAME}.zip
close
bye
EOF

上面介绍的是shell脚本,当然也可以通过编写Python脚本实现ftp传输文件。ftplib模块中的FTP()类可以实现此功能。下面介绍一些FTP()类中的方法。

  • connect(host=‘’, port=0, timeout=-999)
    链接ftp服务器主机
  • login(user = ‘’, passwd = ‘’, acct = ‘’)
    使用用户名和密码进行登录,acct是登录成功后访问资源所需的补充密码
  • set_debuglevel(level)
    设置调试级别,level有三个级别:
    0:没有调试输出(默认)
    1:打印命令和响应,但不打印正文等
    2:还打印读取和发送的原始行中CR/LF前的内容
  • getwelcome()
    打印ftp服务器的欢迎信息
  • cwd(dirname)
    进入目录
  • mkd(dirname)
    创建目录,返回目录的完整路径名
  • rename(fromname, toname)
    重命名文件
  • nlst(*args)
    返回给定目录下的文件列表,默认返回当前目录文件列表
  • quit()
    离开并关闭连接
  • retrbinary(cmd, callback, blocksize=8192, rest=None)
    以二进制模式检索数据,并为你创建一个新的端口
    cmd :RETR命令
    callback :在读取的每个数据块上可调用的单个参数,即读取到的数据的回调函数
    blocksize :一次从套接字读取的最大字节数。[默认值:8192 ]
  • storbinary(cmd, fp, blocksize=8192, callback=None, rest=None)
    以二进制模式存储文件。为您创建了一个新的端口。
    cmd :STOR命令
    fp :一个具有read(num_bytes)方法的类文件对象
    blocksize :一次从fp读取并发送给连接的数据大小[默认值:8192 ]

了解了FTP()类的方法的之后,我们可以封装一个方便自己使用的类,这个类主要实现上传和下载文件或文件夹,这样做的好处是在使用时快速实现,减少代码量,具体代码如下:

# -*- coding: utf-8 -*-    
from ftplib import FTP 
import os     

class FTPUtil():

    DEFAULT_TIME_OUT = 30

    def __init__(self, username, password, server, port=21):
        self.username = username
        self.pasword = password
        self.server = server
        self.port = port 
        self.ftp = self._connect() 

    def _connect(self):  
        ftp_server = self.server  # FTP server ip address  
        username = self.username  
        password = self.pasword    
        timeout = self.DEFAULT_TIME_OUT
        port = self.port  

        ftp = FTP()    
        ftp.set_debuglevel(1)    
        ftp.set_pasv(False)
        ftp.connect(ftp_server, port, timeout)  # connect to FTP server  
        ftp.login(username, password)     
        print ftp.getwelcome()  # can display FTP server welcome message.    
        return ftp    

    def _makeRemotePath(self, target_dir):
        self.ftp.cwd('/')
        target_dir.strip('/')
        dir_items = target_dir.split('/')
        for item in dir_items:
            try:
                self.ftp.cwd(item)
            except:
                self.ftp.mkd(item)
                self.ftp.cwd(item)

    def _makeLocalPath(self, target_dir):
        if not os.path.isdir(target_dir):
            os.makedirs(target_dir)

    def downloadfile_from_FTP(self, remote_file, local_dir):  
        bufsize = 1024  # set buffer size  

        file_name = remote_file.split('/')[-1]
        self._makeLocalPath(local_dir)

        fp = open(os.path.join(local_dir,file_name), "wb")   
        # start to download file :FTP server --> local
        self.ftp.retrbinary('RETR %s' % remote_file, fp.write, bufsize)      

        fp.close()  # close connect    

        print "download finished!"

    def uploadfile_to_FTP(self, local_file, remote_dir):  
        bufsize = 1024    

        file_name = local_file.split('/')[-1]
        self._makeRemotePath(remote_dir)

        fp = open(local_file, 'rb')    
        # start to upload file :local --> FTP server 
        self.ftp.storbinary('STOR ' + file_name, fp, bufsize)   

        fp.close()  # close connect    

        print "upload finished!"

    def downloaddir_from_FTP(self, remote_dir, local_dir):
        #self._makeLocalPath(local_dir)

        self.ftp.cwd(remote_dir)
        remotenames = self.ftp.nlst()
        for remote_file in remotenames:
            self.downloadfile_from_FTP(remote_file,local_dir)  

    def uploaddir_to_FTP(self, local_dir, remote_dir):
        #self._makeRemotePath(remote_dir) 
        for filename in os.listdir(local_dir):
            local_file = os.path.join(local_dir,filename)
            self.uploadfile_to_FTP(local_file, remote_dir) 

    def rename_filename_from_FTP(self, path, old_name, new_name):
        self.ftp.cwd(path) 
        self.ftp.rename(old_name, new_name)
        print "rename finished!"

    def get_filesname_from_FTP(self, path):
        self.ftp.cwd(path) 
        return self.ftp.nlst()

    def close(self):
        self.ftp.quit()

if __name__ == "__main__":  
    ftp_util = FTPUtil("abc", "***", "61.**.**")
    print ftp_util.get_filesname_from_FTP("/")
    ftp_util.close()

在这个封装的FTPUTil()类中,初始化参数有ftp服务器地址,用户名和密码,端口默认是21,而初始化类后即登录ftp,默认登录超时时间的30秒。然后就可以调用传输文件或文件夹的方法,传输文件夹的方法是遍历文件夹下面的文件,然后传输单个文件。

有时,我们传输文件的目标路径文件夹可能不存在,因此传输文件前要先检查目录是否存在,_makeRemotePath()和_makeLocalPath()方法分别检查远程目录和本地目录,如果不存在则创建,其中_makeRemotePath()方法是将路径分割,尝试依次进入,如果进入失败,则说明此目录不存在,则创建。调用此方法后,当前工作目录就是目标目录。

downloadfile_from_FTP()和uploadfile_to_FTP()分别实现下载文件和上传文件,而参数都是源文件和目标目录,这里我们默认传输文件后文件名保持不变。downloaddir_from_FTP()和uploaddir_to_FTP()分别实现下载和长传文件夹。

当然,也可以根据自己需要实现其他的方法,比如rename_filename_from_FTP(),在最后不要忘了关闭ftp链接(close())。

SFTP

SFTP也可以以交互的方式登录,登录命令为 sftp -P port user@host,如下图所示:

在这里插入图片描述
登录成功后就可以传输文件,常用的命令和ftp差不多,这里不再赘述,可以通过info sftp查看更多命令详情。但是如果要自动输入密码,就要借助其他软件,可用的有lftp、sshpass等。这里使用sshpass。具体的shell脚本见下:

#!/bin/bash
TODAY=$(date +%Y%m%d)
#TODAY=20180806
TODAY_NAME=$(date +%m%d)
#TODAY_NAME=0806
HOST=61.**.**
PORT=22
USER=abc
PASSWD=****
export SSHPASS=$PASSWD
sshpass -e sftp -oBatchMode=no -oport=22 $USER@$HOST << !
lcd /home/songzp
cd upload
mkdir ${TODAY}
cd ${TODAY}
put ${TODAY_NAME}.zip
close
bye
!

其中-e 的意思是密码通过环境变量SSHPASS获得,变量名称必须是“SSHPASS”。当然,密码也可以通过文件或其他方式获得。

在Python环境下,可以使用paramiko模块实现sftp传输文件。同样的方法,我们封装一个方便自己使用的工具类SFTPUtils()类,具体代码如下:

# coding=utf-8
'''
Created on 2018年4月26日

@author: Administrator
'''
import os 
import paramiko 

class SftpUtils(object):
    def __init__(self, host, port, user, password):
        self._host = host 
        self._port = port 
        self._user = user 
        self._password = password 
        self.SFTP = self._connect()   

    def _connect(self):
        u"""
 链接SFTP
        """
        try:
            transport = paramiko.Transport((self._host,self._port))
            transport.connect(username=self._user,password=self._password)
            SFTP = paramiko.SFTPClient.from_transport(transport)            
            print u"链接成功..."
            return SFTP  
        except Exception as e:
            print u"连接失败..%s" % e 

    def _makeRemotePath(self, target): 
        u"""
 创建目标路径
 说明: 目标路径不存在则依次创建路径目录
        """
        # 切换根目录
        self.SFTP.chdir('/')
        # 分割目标目录为目录单元集合
        target.strip('/')
        data = target.split('/')  
        # 进入目标目录, 目录不存在则创建
        for item in data:
           try: 
               self.SFTP.chdir(item) 
               print u'要上传的目录已经存在,选择性进入合并:' + item   
           except:
               self.SFTP.mkdir(item)  
               self.SFTP.chdir(item) 
               print u'要上传的目录不存在,创建目录:' + item   

    def _makeLocalPath(self, target_dir):
        if not os.path.isdir(target_dir):
            os.makedirs(target_dir)   

    def upload_file(self, localfile, remotedir):     
        u"""
 传输单个文件
        """
        self._makeRemotePath(remotedir)
        filename = localfile.split('/')[-1]       
        # 上传文件
        try:            
            self.SFTP.put(localfile, filename)            
            print u'%s 上传成功:' % filename        
        except Exception as e:            
            print u'%s 上传失败:%s' % (filename, str(e)) 

    def download_file(self, remotefile, localdir):        
        u"""
 下载单个文件
        """
        filename = remotefile.split('/')[-1]        
        self._makeLocalPath(localdir)        
        # 下载文件
        try:            
            self.SFTP.get(remotefile, os.path.join(localdir, filename))        
        except Exception as e:            
            print u'%s 下载失败:%s' % (filename, str(e))  

    def upload_dir(self, localdir, remotedir): 
        for filename in os.listdir(localdir):
            localfile = os.path.join(localdir, filename) 
            self.upload_file(localfile, remotedir)

    def download_dir(self, remotedir, localdir):   
        self.SFTP.chdir(remotedir) 
        for remote_file in self.SFTP.listdir(remotedir):            
            self.download_file(remote_file, localdir)    
            
    def close(self):        
        self.SFTP.close()
if __name__ == '__main__':
    sftp = SftpUtils("61.***.**",22,"abc","***")
    sftp.upload_file("/home/songzp/20181016.zip","/upload/20181016/20181016.zip")
    sftp.close()

SFTP通过Transport()类登录,host和port可以作为元组传入,就像代码中的那样,也可以组合为“host:port”字符串传入,登录SFTP后,下载和上传文件直接通过get()方法和put()方法轻松实现,但是这两个方法的目标路径参数必须是文件,不能是一个目录。


有时会遇到需要通过TLS/SSL加密的方式连接FTP,可以使用lftp,不过Python的ftplib模块中的FTP_TLS()类可以实现,该类继承自FTP()类,因此使用方法一样。关于FTP与SFTP的内容还有很多,本文本着会使用的初衷,简单介绍了传输文件的方法,更多更详细的知识还需进一步探索实践。

转载至FTP与SFTP传输文件的Python、shell脚本_python sftp_追光的鲲的博客-CSDN博客

  • 0
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 以下是一个示例的shell脚本,用于实现sftp文件传输: ```bash #!/bin/bash #sftp服务器地址 host="192.168.149.128" #端口 port=22 sftp_user="sftp" #密码 password="123456" #下载到本地的目录 localDir="/tmp" \[ ! -d $localDir \] && mkdir -p $localDir #sftp中待下载文件目录 remoteDir="/" #要下载的文件为fileName fileName="data.log" lftp -u ${sftp_user},${password} sftp://${host}:${port}<<EOF cd ${remoteDir} lcd ${localDir} get $fileName by EOF ``` 这个脚本使用lftp命令来实现sftp文件传输。首先,设置sftp服务器的地址、端口、用户名和密码。然后,指定要下载的文件的路径和本地目录。最后,使用lftp命令连接到sftp服务器,并执行cd命令切换到远程目录,lcd命令切换到本地目录,get命令下载指定的文件。\[1\] 如果你想实现文件上传,可以使用以下示例脚本: ```bash #!/bin/bash #SFTP配置信息 #用户名 USER=jijian #密码 PASSWORD=jj #待上传文件根目录 SRCDIR=/home/databackup #SFTP目录 DESDIR=/home/jijian #IP IP=10.2.5.142 #端口 PORT=22 #获取文件 cd ${SRCDIR} #目录下的所有文件 #FILES=`ls` #查找后缀为txt的文件 FILES=`find ${SRCDIR} -name '*.txt'` for FILE in ${FILES} do echo ${FILE} #发送文件 (关键部分) #复制出来,如有结尾有空格,请自行去掉 lftp -u ${USER},${PASSWORD} sftp://${IP}:${PORT}<<EOF cd ${DESDIR}/ lcd ${SRCDIR} put ${FILE} by EOF done ``` 这个脚本使用lftp命令来实现sftp文件上传。首先,设置sftp服务器的地址、端口、用户名和密码。然后,指定要上传的文件的根目录和sftp目录。接下来,使用cd命令切换到待上传文件的根目录,获取所有文件的列表。最后,使用lftp命令连接到sftp服务器,并执行cd命令切换到sftp目录,lcd命令切换到待上传文件的根目录,put命令上传指定的文件。\[2\] 如果你想实现sftp文件同步,可以使用以下示例脚本: ```bash #!/bin/bash #sftp服务器地址 host="192.168.149.128" #端口 port=22 sftp_user="sftp" #密码 password="123456" #下载到本地的目录 localDir="/data/logs/sftp_logs" \[ ! -d $localDir \] && mkdir -p $localDir #sftp中待下载的文件目录 remoteDir1="/oslog" remoteDir2="/data" lftp -u ${sftp_user},${password} sftp://${host}:${port}<<EOF cd / lcd ${localDir} mirror ${remoteDir1} mirror ${remoteDir2} by EOF ``` 这个脚本使用lftp命令来实现sftp文件同步。首先,设置sftp服务器的地址、端口、用户名和密码。然后,指定要下载到本地的目录和sftp中待下载的文件目录。接下来,使用lftp命令连接到sftp服务器,并执行cd命令切换到根目录,lcd命令切换到本地目录,mirror命令同步指定的远程目录到本地目录。\[3\] #### 引用[.reference_title] - *1* *3* [使用shell脚本下载sftp文件](https://blog.csdn.net/d1240673769/article/details/106307421)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [linux下用shell脚本实现sftp文件上传](https://blog.csdn.net/weixin_42952472/article/details/123378125)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值