golang实现从服务器下载文件到本地指定目录

一、连接服务器,采用sftp连接模式

go 复制代码
package middlewares

import (
	"fmt"
	"time"

	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
)

// 建立服务器连接
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: []ssh.AuthMethod{ssh.Password(password)},
		// 此处忽略了密钥认证,改用密码认证
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Timeout:         30 * time.Second,
	}
	// 通过ssh连接到服务器
	addr = fmt.Sprintf("%s:%d", host, port)
	if sshClient, err = ssh.Dial("tcp", addr, clientConfig); err != nil {
		return nil, err
	}
	// 创建一个sftp连接工具用来读取文件或者目录
	if sftpClient, err = sftp.NewClient(sshClient); err != nil {
		return nil, err
	}
	return sftpClient, nil
}

二、下载文件

go 复制代码
// 定义下载功能
func SyncCiticLog(r *gin.Context) {
	// viper设置的连接服务器的用户名和密码以及端口、连接的IP地址,此用户名写在了配置文件中
	User := viper.GetString("ConnectUser")
	Password := viper.GetString("ConnectPassword")
	Port := viper.GetInt("ConnectPort")
	citicIp := viper.GetString("ConnectOldIp")
	// 此处设置了要读取的目录前缀
	const allDir = "D:\\backup\\citic"
	// 定义变量用来接收下载文件的源目录和目标目录
	dstDir := ""
	srcDir := ""
	// 实例化结构体用来接收数据
	downloglist := DownLogList{}
	// 调用定义的sftp方法连接服务器
	sftpClient, sftpErr := middlewares.Connect(User, Password, citicIp, Port)
	// 此处要关闭要用defer关闭连接,否则下载的文件将发生打开文件错误
	defer sftpClient.Close()
	// 判断连接是否成功
	if sftpErr != nil {
		logs.Error(map[string]interface{}{"msg": sftpErr}, "未连接到服务器,请检查相关配置!")
	}
	// 此处用的Post请求,在请求体获取前端传递过来的参数
	if error := r.ShouldBindBodyWithJSON(&downloglist); error != nil {
		logs.Error(map[string]interface{}{"msg": "绑定结构体失败"}, "请检查配置文件是否正确!")
	} else {
		// 判断传递过来的IP,来定义相应的源目录和目标目录
		switch downloglist.ServiceIp {
		case "172.16.2.51":
			srcDir = "/home/backup/zqyl-abc/new"
			dstDir = "D:\\backup\\abc"
			break
		case "172.16.2.58":
			srcDir = "/home/backup/citic/" + downloglist.ServiceIp
			dstDir = filepath.Join(allDir, "中信03")
			break
		case "172.16.2.59":
			srcDir = "/home/backup/citic/" + downloglist.ServiceIp
			dstDir = filepath.Join(allDir, "中信04")
			break
		case "172.16.2.60":
			srcDir = "/home/backup/citic/" + downloglist.ServiceIp
			dstDir = filepath.Join(allDir, "中信01")
			break
		case "172.16.2.61":
			srcDir = "/home/backup/citic/" + downloglist.ServiceIp
			dstDir = filepath.Join(allDir, "中信02")
			break
		}
		// 由于传递过来的下载文件是多个,所以将以集合的形式传递过来,循环遍历来将单个文件进行下载
		for _, citicLog := range downloglist.LogList {
			// 拼出源文件的位置目录
			fileSrcDir := srcDir + "/" + citicLog
			// 利用sftp连接工具将文件目录打开
			openFile, err := sftpClient.Open(fileSrcDir)
			if err != nil {
				logs.Error(map[string]interface{}{"msg": "读取文件失败!"}, "请检查文件是否存在或者是否正常!")
			}
			// 创建本地文件存放的目录
			error := os.MkdirAll(dstDir, 0755)
			if error != nil {
				logs.Error(map[string]interface{}{"msg": "创建文件失败!"}, "请检查目录是否存在!")
			}
			// 创建本地文件的等待拷贝
			logFile, _ := os.Create(dstDir + "\\" + citicLog)
			// 创建资源记得关闭
			defer logFile.Close()
			// 拷贝文件至目标目录
			_, copyErr := io.Copy(logFile, openFile)
			if copyErr != nil {
				logs.Info(map[string]interface{}{"msg": "下载文件失败,请检查磁盘分区是否存在或者是否可写入状态!!"}, "")
			}
		}
		// 返回给前端状态码、下载成功信息、目标文件下载到的目录
		r.JSON(http.StatusOK, gin.H{
			"status":  http.StatusOK,
			"message": "下载成功!",
			"path":    dstDir,
		})
	}
}
相关推荐
Wang's Blog5 小时前
Java 项目实战: 交友项目 - FastDFS:入门案例
java·开发语言·交友
apcipot_rain6 小时前
C++转Java日记(03)
java·开发语言·c++
布莱克6056 小时前
C++ 中 map 的 insert 与 emplace:key 已存在时会覆盖吗?
开发语言·数据结构·c++·算法·map
xys_6786 小时前
深挖C++:类和对象(中)
开发语言·c++
灿飞屋7 小时前
Rust 编程其实很简单
开发语言·rust
MOONICK8 小时前
QT元数据
开发语言·qt
D e re k ZH9 小时前
C++ 系统学习手记:从语法细节到工程实践
开发语言·数据结构·c++·算法
灿飞屋10 小时前
Kotlin与Java虚拟机三:控制流
android·java·开发语言·后端·python·kotlin·安卓
迪康coolmu10 小时前
出差终端数据安全落地实战:基于迪康端点安全一体化管理系统的四道防线实践
运维·服务器·经验分享·笔记·其他·安全·php
xiaoye-duck10 小时前
《C++ 项目:手写大模型接入 SDK》Ollama接口设计(上):初始化、全量响应实现和测试
开发语言·网络·c++·语言模型