Golang FTP文件下载实现方案

在Golang中实现FTP文件下载时,使用标准库还是第三方库更合适?有没有推荐的稳定库?需要注意哪些常见问题,比如断点续传、连接超时或大文件下载的性能优化?能否提供一个简单的代码示例?

2 回复

在Golang中实现FTP文件下载,可以使用官方net/ftp包。以下是核心实现步骤:

  1. 建立FTP连接:
conn, err := ftp.Dial("host:port")
conn.Login("user", "password")
  1. 切换目录(可选):
conn.ChangeDir("/remote/path")
  1. 下载文件:
// 方法1:直接读取到内存
reader, _ := conn.Retr("filename.txt")
buf, _ := io.ReadAll(reader)
reader.Close()

// 方法2:写入本地文件
file, _ := os.Create("local.txt")
conn.Retr("filename.txt", file)
file.Close()
  1. 错误处理和资源清理:
  • 确保关闭Reader和连接
  • 添加超时控制
  • 检查文件大小和权限

注意事项:

  • 使用conn.Quit()关闭连接
  • 大文件建议分块下载
  • 生产环境需添加重试机制
  • 考虑使用TLS加密连接(ftps)

完整示例约50行代码即可实现基础下载功能。

更多关于Golang FTP文件下载实现方案的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Golang中实现FTP文件下载,可以通过标准库net/ftp来完成。以下是完整的实现方案:

核心代码实现

package main

import (
    "fmt"
    "io"
    "net/ftp"
    "os"
    "path/filepath"
    "time"
)

// FTPClient 封装FTP客户端
type FTPClient struct {
    client *ftp.ServerConn
}

// NewFTPClient 创建FTP客户端连接
func NewFTPClient(host, user, password string, port int) (*FTPClient, error) {
    addr := fmt.Sprintf("%s:%d", host, port)
    conn, err := ftp.Dial(addr, ftp.DialWithTimeout(30*time.Second))
    if err != nil {
        return nil, fmt.Errorf("连接FTP服务器失败: %v", err)
    }

    err = conn.Login(user, password)
    if err != nil {
        return nil, fmt.Errorf("FTP登录失败: %v", err)
    }

    return &FTPClient{client: conn}, nil
}

// DownloadFile 下载单个文件
func (fc *FTPClient) DownloadFile(remotePath, localPath string) error {
    // 创建本地目录
    dir := filepath.Dir(localPath)
    if err := os.MkdirAll(dir, 0755); err != nil {
        return fmt.Errorf("创建本地目录失败: %v", err)
    }

    // 创建本地文件
    localFile, err := os.Create(localPath)
    if err != nil {
        return fmt.Errorf("创建本地文件失败: %v", err)
    }
    defer localFile.Close()

    // 从FTP服务器读取文件
    reader, err := fc.client.Retr(remotePath)
    if err != nil {
        return fmt.Errorf("读取远程文件失败: %v", err)
    }
    defer reader.Close()

    // 复制文件内容
    _, err = io.Copy(localFile, reader)
    if err != nil {
        return fmt.Errorf("下载文件失败: %v", err)
    }

    fmt.Printf("文件下载成功: %s -> %s\n", remotePath, localPath)
    return nil
}

// Close 关闭连接
func (fc *FTPClient) Close() error {
    if fc.client != nil {
        return fc.client.Quit()
    }
    return nil
}

// 使用示例
func main() {
    // 连接FTP服务器
    client, err := NewFTPClient("ftp.example.com", "username", "password", 21)
    if err != nil {
        fmt.Printf("错误: %v\n", err)
        return
    }
    defer client.Close()

    // 下载文件
    err = client.DownloadFile("/remote/path/file.txt", "./local/file.txt")
    if err != nil {
        fmt.Printf("下载失败: %v\n", err)
        return
    }
}

高级功能扩展

1. 批量下载文件

// DownloadMultipleFiles 批量下载文件
func (fc *FTPClient) DownloadMultipleFiles(fileMap map[string]string) error {
    for remotePath, localPath := range fileMap {
        if err := fc.DownloadFile(remotePath, localPath); err != nil {
            return fmt.Errorf("下载 %s 失败: %v", remotePath, err)
        }
    }
    return nil
}

2. 下载整个目录

// DownloadDirectory 下载整个目录
func (fc *FTPClient) DownloadDirectory(remoteDir, localDir string) error {
    entries, err := fc.client.List(remoteDir)
    if err != nil {
        return err
    }

    for _, entry := range entries {
        remotePath := remoteDir + "/" + entry.Name
        localPath := filepath.Join(localDir, entry.Name)

        if entry.Type == ftp.EntryTypeFolder {
            // 递归下载子目录
            fc.DownloadDirectory(remotePath, localPath)
        } else {
            // 下载文件
            fc.DownloadFile(remotePath, localPath)
        }
    }
    return nil
}

关键要点

  1. 连接管理: 使用DialWithTimeout设置连接超时
  2. 错误处理: 对每个操作进行错误检查
  3. 资源清理: 使用defer确保连接和文件正确关闭
  4. 目录创建: 自动创建本地目录结构

这个方案提供了稳定可靠的FTP文件下载功能,可以根据实际需求进行扩展。

回到顶部