- Client">type Client
- ClientOption">type ClientOption
- File">type File
- 例子:
- ftp使用记录
import “golang.org/x/crypto/ssh”
文档 https://godoc.org/github.com/pkg/sftp
type Client
func NewClient(conn ssh.Client, opts …ClientOption) (Client, error)
func (c Client) Chmod(path string, mode os.FileMode) error 更改指定文件的权限
func (c Client) Chown(path string, uid, gid int) error 更改指定文件的用户和组所有者
func (c Client) Chtimes(path string, atime time.Time, mtime time.Time) error 更改指定文件的访问和修改时间func (c Client) Close() error
func (c Client) Create(path string) (File, error) 以0666权限创建文件并打开,如果该文件存在相当于删除后再打开
func (c Client) Getwd() (string, error) 返回当前工作目录
func (c Client) Glob(pattern string) (matches []string, err error) 返回所有匹配模式的文件的名称
func (c Client) Link(oldname, newname string) error 创建link
func (c Client) Mkdir(path string) error 创建文件夹,如果指定路径的文件或目录已经存在,或者该目录的父文件夹不存在,返回错误
func (c Client) MkdirAll(path string) error 创建一个名为path的目录,以及所有必要的父目录,并返回nil
func (c Client) Open(path string) (File, error) 以只读打开一个文件
func (c Client) ReadDir(p string) ([]os.FileInfo, error) 打开文件夹
func (c Client) ReadLink(p string) (string, error) 读取符号链接的目标
func (c Client) Remove(path string) error 删除文件或目录。如果路径不存在,或目录不是空的,则返回错误。
func (c Client) RemoveDirectory(path string) error 递归删除
func (c Client) Rename(oldname, newname string) error 重命名
func (c *Client) Stat(p string) (os.FileInfo, error) Stat返回一个FileInfo结构,描述路径“p”指定的文件。如果“p”是一个符号链接,则返回的FileInfo结构将描述引用文件。
type ClientOption
type ClientOption func(*Client) error
func MaxConcurrentRequestsPerFile(n int) ClientOption 置单个文件允许的最大并发请求。默认64
func MaxPacket(size int) ClientOption
func MaxPacketChecked(size int) ClientOption
func MaxPacketUnchecked(size int) ClientOption
func UseFstat(value bool) ClientOption
type File
func (f File) Chmod(mode os.FileMode) error
func (f File) Chown(uid, gid int) error
func (f File) Close() error
func (f File) Name() string
func (f File) Read(b []byte) (int, error)
func (f File) ReadFrom(r io.Reader) (int64, error) 读取数据并将其写入文件(这种方法比多次调用Write更可取)
func (f File) Stat() (os.FileInfo, error)
func (f File) Write(b []byte) (int, error)
func (f *File) WriteTo(w io.Writer) (int64, error) 将文件写入w
例子:
package service
import (
"errors"
"fmt"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"io"
"io/ioutil"
"net"
"os"
"path"
"strings"
"time"
)
type SshServer struct {
}
// 连接到ssh的struct
type SshInfoModel struct {
User string
PassWord string
Host string
Port string
KeyPath string //暂时不用到,之后可能用密钥进行连接
}
/**
* SSH连接 超时参数(秒)
*/
const SSH_CONNECT_TIMEOUT time.Duration = 30
/**
* SSH连接
*/
func SSHConnect(username, password, host string, port int) (*ssh.Client, error) {
var (
sshClient *ssh.Client
clientConfig *ssh.ClientConfig
err error
)
clientConfig = &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.Password(password),
},
//需要验证服务端,不做验证返回nil就可以,点击HostKeyCallback看源码就知道了
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
// fmt.Println("============>", hostname, remote, key)
return nil
},
Timeout: SSH_CONNECT_TIMEOUT * time.Second,
}
// connet to ssh
if sshClient, err = ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), clientConfig); err != nil {
return nil, err
}
return sshClient, nil
}
/**
* SSH客户端获取Session客户端
*/
func GetSSHClientSession(sshClient *ssh.Client) (*ssh.Session, error) {
var sessionClient *ssh.Session
var err error
// create session
if sessionClient, err = sshClient.NewSession(); err != nil {
return nil, err
}
return sessionClient, nil
}
/**
* SSH客户端获取Ftp客户端
*/
func GetSSHClientFtp(sshClient *ssh.Client) (*sftp.Client, error) {
var sftpClient *sftp.Client
var err error
// create sftp client
if sftpClient, err = sftp.NewClient(sshClient); err != nil {
return nil, err
}
return sftpClient, nil
}
/**
* SSH客户端Ftp上传文件到目标服务端(注意是上传文件)
* localFilePath:客户端文件位置
* remotePath:上传的目标路径
*/
func SFTPUploadFile(sftpClient *sftp.Client, localFilePath string, remotePath string) error {
srcFile, err := os.Open(localFilePath)
if err != nil {
return err
}
defer srcFile.Close()
var remoteFileName = path.Base(localFilePath)
dstFile, err := sftpClient.Create(path.Join(remotePath, remoteFileName))
if err != nil {
return err
}
defer dstFile.Close()
buf := make([]byte, 1024)
for {
n, _ := srcFile.Read(buf)
if n == 0 {
break
}
dstFile.Write(buf[0:n])
}
return nil
}
/**
* SSH客户端Ftp上传文件夹到目标服务端(注意是上传文件夹)
* localFile:客户端文件夹位置
* remotePath:上传的目标路径
*/
func SFTPUploadDirectory(sftpClient *sftp.Client, localPath string, remotePath string) {
localFiles, err := ioutil.ReadDir(localPath)
if err != nil {
return
}
for _, backupDir := range localFiles {
localFilePath := path.Join(localPath, backupDir.Name())
remoteFilePath := path.Join(remotePath, backupDir.Name())
if backupDir.IsDir() {
err = sftpClient.Mkdir(remoteFilePath)
if err != nil {
return
}
SFTPUploadDirectory(sftpClient, localFilePath, remoteFilePath)
} else {
err = SFTPUploadFile(sftpClient, path.Join(localPath, backupDir.Name()), remotePath)
if err != nil {
return
}
}
}
}
/**
* SSH客户端Ftp上传文件到目标服务端(注意是上传文件)
* io.Reader:文件流
* allPath:上传的目标路径含文件名
*/
func SFTPUploadFileReader(sftpClient *sftp.Client, file io.Reader, allPath string) error {
dstFile, err := sftpClient.Create(allPath)
if err != nil {
return err
}
defer dstFile.Close()
buf := make([]byte, 1024)
for {
n, _ := file.Read(buf)
if n == 0 {
break
}
dstFile.Write(buf[0:n])
}
return nil
}
ftp使用记录
ftp传包比scp慢很多,确定不是带宽问题,经过排查是缓冲区给太少的原因,代码如下
/**
* SSH客户端Ftp上传文件到目标服务端(注意是上传文件)
* localFilePath:客户端文件位置
* remotePath:上传的目标路径
*/
func SFTPUploadFile(sftpClient *sftp.Client, localFilePath string, remotePath string) error {
srcFile, err := os.Open(localFilePath)
if err != nil {
return err
}
defer srcFile.Close()
var remoteFileName = path.Base(localFilePath)
dstFile, err := sftpClient.Create(path.Join(remotePath, remoteFileName))
if err != nil {
return err
}
defer dstFile.Close()
buf := make([]byte, 1024) // 将缓冲区扩大100倍,及1024*100即可
for {
n, _ := srcFile.Read(buf)
if n == 0 {
break
}
dstFile.Write(buf[0:n])
}
return nil
}