You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#实现FTP文件下载并获取文件大小计算下载进度

FTP下载时同时获取文件大小并计算进度的问题

我编写了一段C#代码,想要从FTP服务器下载文件的同时获取该文件的大小,以此计算下载进度。目前我的代码无法正确计算进度百分比,原因是无法获取待下载文件的大小。若将请求方法从WebRequestMethods.Ftp.DownloadFile改为WebRequestMethods.Ftp.GetFileSize,虽能获取文件大小,但无法进行下载操作。请问有没有办法同时实现获取文件大小与下载文件?

原代码如下:

FtpWebRequest request2 = (FtpWebRequest)WebRequest.Create("ftp://username@127.0.0.1/myfile.zip");
request2.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse response2 = (FtpWebResponse)request2.GetResponse();
responseStream = response2.GetResponseStream();

using (StreamReader reader = new StreamReader(responseStream))
{
    //Console.WriteLine(reader.ReadToEnd());

    // get the current date as DD-MMM-YYYY
    DateTime dt = System.DateTime.Now;
    string fdate = String.Format("{0:dd_MMM_yyyy}", dt);
    string fdate2 = fdate.ToUpper(); // convert to uppercase

    int length = (int)request2.GetResponse().ContentLength;
    //double length = response2.ContentLength;
    long downloaded = 0;
    long result = 0;
    int bufferSize = 32 * 1024;
    byte[] buffer = new byte[bufferSize];

    using (FileStream writer = new FileStream("MYFILE" + fdate2 + ".ZIP", FileMode.Create))
    {
        Console.Write("\r\nMYFILE.ZIP = {0:N0} Bytes ({1:N0} Megabytes).\r\n", length, length/1024); // format the filesize with a comma
        Console.Write("NOTE: Press [CTRL+C] to cancel and terminate this program at anytime...\r\n\r\n");

        int readCount = responseStream.Read(buffer, 0, bufferSize);

        while (readCount > 0)
        {
            writer.Write(buffer, 0, readCount); // byte

            readCount = responseStream.Read(buffer, 0, bufferSize);
            downloaded += readCount; // increment

            double dProgress = ((double)downloaded / length) * 100.0;
            result = Convert.ToInt32(dProgress);
            Console.ForegroundColor = ConsoleColor.Green;
            Console.Write("\r   DOWNLOADING 1/1... {0}%", result);
        }
    }

    Console.ForegroundColor = ConsoleColor.Gray;
    Console.WriteLine("\r\n\r\nDownload Complete! STATUS: {0}", response2.StatusDescription);

    reader.Close();
}

解决方案

可以通过两次独立的FTP请求实现需求:先发送GetFileSize请求获取文件大小,再发送DownloadFile请求执行下载并计算进度。同时需要修正原代码中的几个错误:

原代码问题点

  1. 重复调用request2.GetResponse()获取ContentLength,会创建新的响应连接,属于无效操作,且FtpWebResponse.ContentLength在下载请求中并非100%可靠。
  2. 使用StreamReader处理ZIP等二进制文件,可能因编码问题导致文件损坏。
  3. 进度累加逻辑错误,downloaded += readCount在读取之后执行,会遗漏最后一次读取的字节数。

修正后的代码

string ftpUrl = "ftp://username@127.0.0.1/myfile.zip";
string saveFileName = $"MYFILE{DateTime.Now.ToString("dd_MMM_yyyy").ToUpper()}.ZIP";
int bufferSize = 32 * 1024;

// 第一步:获取目标文件的大小
long totalFileSize = 0;
FtpWebRequest sizeRequest = (FtpWebRequest)WebRequest.Create(ftpUrl);
sizeRequest.Method = WebRequestMethods.Ftp.GetFileSize;
// 若FTP服务器需要密码验证,取消注释并填写正确凭据
// sizeRequest.Credentials = new NetworkCredential("your_username", "your_password");
using (FtpWebResponse sizeResponse = (FtpWebResponse)sizeRequest.GetResponse())
{
    totalFileSize = sizeResponse.ContentLength;
}

// 第二步:执行文件下载并计算进度
FtpWebRequest downloadRequest = (FtpWebRequest)WebRequest.Create(ftpUrl);
downloadRequest.Method = WebRequestMethods.Ftp.DownloadFile;
// downloadRequest.Credentials = new NetworkCredential("your_username", "your_password");
using (FtpWebResponse downloadResponse = (FtpWebResponse)downloadRequest.GetResponse())
using (Stream responseStream = downloadResponse.GetResponseStream())
using (FileStream fileWriter = new FileStream(saveFileName, FileMode.Create))
{
    // 打印文件大小信息
    Console.Write($"\r\nMYFILE.ZIP = {totalFileSize:N0} Bytes ({totalFileSize / 1024 / 1024:N0} Megabytes).\r\n");
    Console.Write("NOTE: Press [CTRL+C] to cancel and terminate this program at anytime...\r\n\r\n");

    byte[] buffer = new byte[bufferSize];
    long downloadedBytes = 0;
    int readBytesCount;

    while ((readBytesCount = responseStream.Read(buffer, 0, bufferSize)) > 0)
    {
        fileWriter.Write(buffer, 0, readBytesCount);
        downloadedBytes += readBytesCount;

        // 计算并打印进度百分比
        double progress = ((double)downloadedBytes / totalFileSize) * 100;
        Console.ForegroundColor = ConsoleColor.Green;
        Console.Write($"\r   DOWNLOADING 1/1... {Math.Round(progress, 1)}%");
    }

    // 下载完成提示
    Console.ForegroundColor = ConsoleColor.Gray;
    Console.WriteLine($"\r\n\r\nDownload Complete! STATUS: {downloadResponse.StatusDescription}");
}

核心说明

  • 分两次请求:先获取文件大小再下载,避免了单次请求中无法同时兼顾大小获取和下载的问题。
  • 直接操作Stream处理二进制文件,避免编码错误导致的文件损坏。
  • 修正进度计算逻辑,确保累加的是已写入文件的字节数,进度显示更准确。
  • 使用Math.Round优化进度百分比的显示精度,可根据需求调整小数位数。

内容的提问来源于stack exchange,提问作者matead

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 04:20:38