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请求执行下载并计算进度。同时需要修正原代码中的几个错误:
原代码问题点
- 重复调用
request2.GetResponse()获取ContentLength,会创建新的响应连接,属于无效操作,且FtpWebResponse.ContentLength在下载请求中并非100%可靠。 - 使用
StreamReader处理ZIP等二进制文件,可能因编码问题导致文件损坏。 - 进度累加逻辑错误,
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
相关产品推荐
相关产品推荐

