go语言实现sftp包上传文件和文件夹到远程服务器操作
作者:奔流入海 发布时间:2024-05-08 10:22:18
标签:go,sftp,服务器,上传
使用go语言的第三方包:github.com/pkg/sftp和golang.org/x/crypto/ssh实现文件和文件夹传输。
1、创建connect方法:
func connect(user, password, host string, port int) (*sftp.Client, error) {
var (
auth []ssh.AuthMethod
addr string
clientConfig *ssh.ClientConfig
sshClient *ssh.Client
sftpClient *sftp.Client
err error
)
// get auth method
auth = make([]ssh.AuthMethod, 0)
auth = append(auth, ssh.Password(password))
clientConfig = &ssh.ClientConfig{
User: user,
Auth: auth,
Timeout: 30 * time.Second,
HostKeyCallback: ssh.InsecureIgnoreHostKey(), //ssh.FixedHostKey(hostKey),
}
// connet to ssh
addr = fmt.Sprintf("%s:%d", host, port)
if sshClient, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
return nil, err
}
// create sftp client
if sftpClient, err = sftp.NewClient(sshClient); err != nil {
return nil, err
}
return sftpClient, nil
}
2、上传文件
func uploadFile(sftpClient *sftp.Client, localFilePath string, remotePath string) {
srcFile, err := os.Open(localFilePath)
if err != nil {
fmt.Println("os.Open error : ", localFilePath)
log.Fatal(err)
}
defer srcFile.Close()
var remoteFileName = path.Base(localFilePath)
dstFile, err := sftpClient.Create(path.Join(remotePath, remoteFileName))
if err != nil {
fmt.Println("sftpClient.Create error : ", path.Join(remotePath, remoteFileName))
log.Fatal(err)
}
defer dstFile.Close()
ff, err := ioutil.ReadAll(srcFile)
if err != nil {
fmt.Println("ReadAll error : ", localFilePath)
log.Fatal(err)
}
dstFile.Write(ff)
fmt.Println(localFilePath + " copy file to remote server finished!")
}
3、上传文件夹
func uploadDirectory(sftpClient *sftp.Client, localPath string, remotePath string) {
localFiles, err := ioutil.ReadDir(localPath)
if err != nil {
log.Fatal("read dir list fail ", err)
}
for _, backupDir := range localFiles {
localFilePath := path.Join(localPath, backupDir.Name())
remoteFilePath := path.Join(remotePath, backupDir.Name())
if backupDir.IsDir() {
sftpClient.Mkdir(remoteFilePath)
uploadDirectory(sftpClient, localFilePath, remoteFilePath)
} else {
uploadFile(sftpClient, path.Join(localPath, backupDir.Name()), remotePath)
}
}
fmt.Println(localPath + " copy directory to remote server finished!")
}
4、上传测试
func DoBackup(host string, port int, userName string, password string, localPath string, remotePath string) {
var (
err error
sftpClient *sftp.Client
)
start := time.Now()
sftpClient, err = connect(userName, password, host, port)
if err != nil {
log.Fatal(err)
}
defer sftpClient.Close()
_, errStat := sftpClient.Stat(remotePath)
if errStat != nil {
log.Fatal(remotePath + " remote path not exists!")
}
backupDirs, err := ioutil.ReadDir(localPath)
if err != nil {
log.Fatal(localPath + " local path not exists!")
}
uploadDirectory(sftpClient, localPath, remotePath)
elapsed := time.Since(start)
fmt.Println("elapsed time : ", elapsed)
}
补充:go实现ssh远程机器并传输文件
核心依赖包:
golang.org/x/crypto/ssh
github.com/pkg/sftp
其中golang.org/x/crypto/ssh 可从github上下载,
下载地址:https://github.com/golang/crypto
ssh连接源码(这里是根据秘钥连接):
var keypath = "key/id_rsa"
//获取秘钥
func publicKey(path string) ssh.AuthMethod {
keypath, err := homedir.Expand(path)
if err != nil {
fmt.Println("获取秘钥路径失败", err)
}
key, err1 := ioutil.ReadFile(keypath)
if err1 != nil {
fmt.Println("读取秘钥失败", err1)
}
signer, err2 := ssh.ParsePrivateKey(key)
if err2 != nil {
fmt.Println("ssh 秘钥签名失败", err2)
}
return ssh.PublicKeys(signer)
}
//获取ssh连接
func GetSSHConect(ip, user string, port int) (*ssh.Client) {
con := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{publicKey(keypath)},
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil
},
}
addr := fmt.Sprintf("%s:%d", ip, port)
client, err := ssh.Dial("tcp", addr, con)
if err != nil {
fmt.Println("Dail failed: ", err)
panic(err)
}
return client
}
// 远程执行脚本
func Exec_Task(ip, user, localpath, remotepath string) int {
port := 22
client := GetSSHConect(ip, user, port)
UploadFile(ip, user, localpath, remotepath, port)
session, err := client.NewSession()
if err != nil {
fmt.Println("创建会话失败", err)
panic(err)
}
defer session.Close()
remoteFileName := path.Base(localpath)
dstFile := path.Join(remotepath, remoteFileName)
err1 := session.Run(fmt.Sprintf("/usr/bin/sh %s", dstFile))
if err1 != nil {
fmt.Println("远程执行脚本失败", err1)
return 2
} else {
fmt.Println("远程执行脚本成功")
return 1
}
}
文件传输功能:
//获取ftp连接
func getftpclient(client *ssh.Client) (*sftp.Client) {
ftpclient, err := sftp.NewClient(client)
if err != nil {
fmt.Println("创建ftp客户端失败", err)
panic(err)
}
return ftpclient
}
//上传文件
func UploadFile(ip, user, localpath, remotepath string, port int) {
client := GetSSHConect(ip, user, port)
ftpclient := getftpclient(client)
defer ftpclient.Close()
remoteFileName := path.Base(localpath)
fmt.Println(localpath, remoteFileName)
srcFile, err := os.Open(localpath)
if err != nil {
fmt.Println("打开文件失败", err)
panic(err)
}
defer srcFile.Close()
dstFile, e := ftpclient.Create(path.Join(remotepath, remoteFileName))
if e != nil {
fmt.Println("创建文件失败", e)
panic(e)
}
defer dstFile.Close()
buffer := make([]byte, 1024)
for {
n, err := srcFile.Read(buffer)
if err != nil {
if err == io.EOF {
fmt.Println("已读取到文件末尾")
break
} else {
fmt.Println("读取文件出错", err)
panic(err)
}
}
dstFile.Write(buffer[:n])
//注意,由于文件大小不定,不可直接使用buffer,否则会在文件末尾重复写入,以填充1024的整数倍
}
fmt.Println("文件上传成功")
}
//文件下载
func DownLoad(ip, user, localpath, remotepath string, port int) {
client := GetSSHConect(ip, user, port)
ftpClient := getftpclient(client)
defer ftpClient.Close()
srcFile, err := ftpClient.Open(remotepath)
if err != nil {
fmt.Println("文件读取失败", err)
panic(err)
}
defer srcFile.Close()
localFilename := path.Base(remotepath)
dstFile, e := os.Create(path.Join(localpath, localFilename))
if e != nil {
fmt.Println("文件创建失败", e)
panic(e)
}
defer dstFile.Close()
if _, err1 := srcFile.WriteTo(dstFile); err1 != nil {
fmt.Println("文件写入失败", err1)
panic(err1)
}
fmt.Println("文件下载成功")
}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持asp之家。如有错误或未考虑完全的地方,望不吝赐教。
来源:https://blog.csdn.net/fu_qin/article/details/78741854


猜你喜欢
- 当我们想复制两个一模一样的列表时,我们可能使用到list.copy()这个方法,这个方法可以让我们复制一个相同的数组,当遇到下面这种情况时,
- 简介Part1:写在最前 OneProxy平民软件完全自主开发的分布式数据访问层,帮助用户在MySQL/
- 前言声明: 以下文章所包含的结论都是基于 typeScript@4.9.4 版本所取得的。extends 是 typeScript 中的关键
- 一、foreach()循环对数组内部指针不再起作用,在PHP7之前,当数组通过foreach迭代时,数组指针会移动。现在开始,不再如此,见下
- 前言本文是美团一位大佬写的,还不错拿出来和大家分享下,代码中嵌套在html中sql语句是java框架的写法,理解其sql要执行的语句即可。背
- 接口性能测试时,接口请求参数是根据一定的规则拼接后进行MD5加密后再进行传参,因此借助于python脚本实现,则可以有效提升测试效率。1.分
- Python通过yield提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。gevent是第
- 前言文接上回,我们已经使用gojs实现了一个最最最基本的树形布局。这次我们开始对图形的骨架进行一个内容展示上的丰富和显示风格上的美化。可以说
- declare @t varchar(255),@c varchar(255)declare table_cursor cursor for
- 最近写一个和二维列表有关的算法时候发现的当用max求二维列表中最大值时,输出的结果是子列表首元素最大的那个列表测试如下c=[[1,2,-1]
- import timenow_time = time.time()print(now_time)结果是1594
- js实现千分符转化function fmoney(s, n){ n = n > 0 && n <= 20 ? n
- 如下所示:a = 1b = 3print(a/b)#方法一:print(round(a/b,2))#方法二:print(format(flo
- 本文介绍使用python+pyqt5开发桌面程序的一个可视化UI视图布局一、环境包的安装1、如果还不知道虚拟环境的可以参考,或者直接使用pi
- 一: 删除LOG1:分离数据库 企业管理器->服务器->数据库->右键->分离数据库2:删除LOG文件3:附加数据库 企业管理器->服务器-
- 什么是wxs?wxs(WeiXin Script)是小程序的一套脚本语言, 结合WXML, 可以构建出页面结构.wxs标签<wxs m
- 1.可以通过settings/dev.py的ALLOWED_HOSTS,设置允许访问# 设置哪些客户端可以通过地址访问到后端 A
- 也不一定,以前从来没有深入的研究过sql查询,最近买了一本T-SQL查询的书,把以前忽视的问题都记录一下 以前一直模模糊糊的把sqlserv
- python3启动web服务引发的一系列问题背景在某行的实施项目,需要使用python3环境运行某些py脚本。由于行内交付的机器已自带pyt
- 前言本文主要介绍的是关于python中open函数用法的相关资料,用法如下:name = open('errname.txt'